home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianTrackControls.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  63KB  |  2,775 lines

  1. /*ScianTrackControls.c
  2.   Eric Pepke
  3.   7 February 1993
  4.  
  5.   Track controls for SciAn
  6.  
  7.   Track controls are used to edit time tracks, such as for keyframe animation.
  8. */
  9.  
  10. #include "Scian.h"
  11. #include "ScianTypes.h"
  12. #include "ScianLists.h"
  13. #include "ScianControls.h"
  14. #include "ScianButtons.h"
  15. #include "ScianTitleBoxes.h"
  16. #include "ScianTextBoxes.h"
  17. #include "ScianColors.h"
  18. #include "ScianIDs.h"
  19. #include "ScianSliders.h"
  20. #include "ScianArrays.h"
  21. #include "ScianErrors.h"
  22. #include "ScianWindows.h"
  23. #include "ScianObjWindows.h"
  24. #include "ScianDraw.h"
  25. #include "ScianIcons.h"
  26. #include "ScianMethods.h"
  27. #include "ScianStyle.h"
  28. #include "ScianHelp.h"
  29. #include "ScianPreferences.h"
  30. #include "ScianSymbols.h"
  31. #include "ScianTrackControls.h"
  32. #include "ScianEvents.h"
  33. #include "ScianTimers.h"
  34. #include "ScianScripts.h"
  35. #include "ScianFontSystem.h"
  36.  
  37. #define DENSITYFACTOR    1.50
  38. #define CEDGE    3            /*Edge in control*/
  39. #define MINNAMESPACE    90
  40. #define MINNOTNAMESPACE    130
  41.  
  42. ObjPtr densityButtonClass;
  43. ObjPtr pictureButtonClass;
  44.  
  45. /*Internal prototypes*/
  46. #ifdef PROTO
  47. static int TimeToPixel(ObjPtr control, real time);
  48. static real PixelToTime(ObjPtr, int);
  49. #else
  50. static int TimeToPixel();
  51. static real PixelToTime();
  52. #endif
  53.  
  54. real timeSteps[] = 
  55.     {
  56.     0.001,
  57.     0.05,
  58.     0.1,
  59.     0.25,
  60.     0.5,
  61.     1.0,
  62.     5.0,
  63.     10.0,
  64.     15.0,
  65.     30.0,
  66.     60.0,
  67.     300.0,
  68.     600.0,
  69.     900.0,
  70.     1800.0,
  71.     3600.0
  72.     };
  73.  
  74. static ObjPtr trackControlClass;    /*Class of all track controls*/
  75.  
  76. #ifdef PROTO
  77. void CalcGeneralSteps(double diff, int pixWidth, int minMajorPix, int minMinorPix, int nSteps, real *steps, double *majorWidth, double *minorWidth)
  78. #else
  79. void CalcGeneralSteps(diff, pixWidth, minMajorPix, minMinorPix, nSteps, steps, majorWidth, nMinorSteps)
  80. double diff;
  81. int pixWidth;
  82. int minMajorPix;
  83. int minMinorPix;
  84. int nSteps;
  85. real *steps;
  86. double *majorWidth;
  87. double *minorWidth;
  88. #endif
  89. /*Calculates good steps for a general scale
  90.     diff is the difference between minimum and max
  91.     pixWidth is the width in pixels between minimum and max
  92.     minMajorPix is the minimum number of pixels between major tics
  93.     minMinorPix is the minimum number of pixels between minor tics
  94.     nSteps is the number of elements in the steps array
  95.     steps is an array of strictly ascending real numbers giving steps
  96.     *majorWidth will be the width of a major step
  97.     *minorWidth will be the width of a minor step
  98.  
  99.   If steps doesn't get big enough, the function will go up in 5, 10 increments
  100.   until arriving at a good value.  If steps doesn't get small enough, the
  101.   function will return the smallest possibility.
  102. */
  103. {
  104.     Bool majorSet;
  105.     Bool minorSet;
  106.     int testPixelWidth;
  107.     int k;
  108.     Bool fiveP;
  109.     real step;
  110.  
  111.     /*Start off with neither set*/
  112.     majorSet = minorSet = false;
  113.  
  114.     /*First excessive increment will be a five*/
  115.  
  116.     for (k = 0; !(majorSet && minorSet); ++k)
  117.     {
  118.     if (k < nSteps)
  119.     {
  120.         step = steps[k];
  121.     }
  122.     else
  123.     {
  124.         if (fiveP)
  125.         {
  126.         step *= 5.0;
  127.         fiveP = false;
  128.         }
  129.         else
  130.         {
  131.         step *= 2.0;
  132.         fiveP = true;
  133.         }
  134.     }
  135.  
  136.     testPixelWidth = step / diff * pixWidth;
  137.  
  138.     if (!majorSet)
  139.     {
  140.         if (testPixelWidth > minMajorPix)
  141.         {
  142.         majorSet = true;
  143.         *majorWidth = step;
  144.         }
  145.     }
  146.     if (!minorSet)
  147.     {
  148.         if (testPixelWidth > minMinorPix)
  149.         {
  150.         minorSet = true;
  151.         *minorWidth = step;
  152.         }
  153.     }
  154.     }
  155. }
  156.  
  157. #define DBINSET        5
  158.  
  159. static ObjPtr DrawDensityButtonContents(theButton)
  160. ObjPtr theButton;
  161. /*Draws the contents of a density button*/
  162. {
  163.     int l, r, b, t;
  164.     int x;
  165.     int step;
  166.     ObjPtr var;
  167.  
  168.     var = GetIntVar("DrawDensityButtonContents", theButton, TICDENSITY);
  169.     if (!var)
  170.     {
  171.     return ObjFalse;
  172.     }
  173.     step = GetInt(var);
  174.  
  175.     Get2DIntBounds(theButton, &l, &r, &b, &t);
  176.  
  177.     for (x = l + DBINSET; x < r - DBINSET; x += step)
  178.     {
  179.     DrawUILine(x, t - DBINSET - 1, x, b + DBINSET, UIBLACK);
  180.     }
  181.  
  182.     return ObjTrue;
  183. }
  184.  
  185. static ObjPtr DrawPictureButton(theButton)
  186. ObjPtr    theButton;
  187. /*Method to draw a picture button.  Adapted from DrawButtonObj*/
  188. {
  189. #ifdef GRAPHICS
  190.     int left, right, bottom, top;
  191.     int        depth;
  192.     Bool    hilight, active;
  193.     ObjPtr    theLabel;
  194.     char    *label;
  195.     ObjPtr    theColor;
  196.     int        color;
  197.     FuncTyp method;
  198.  
  199.     if (!Get2DIntBounds(theButton, &left, &right, &bottom, &top))
  200.     {
  201.     return NULLOBJ;
  202.     }
  203.  
  204.     if (IsDrawingRestricted(left, right, bottom, top))
  205.     {
  206.     return ObjFalse;
  207.     }
  208.  
  209.     hilight = GetPredicate(theButton, HIGHLIGHTED);
  210.     active = GetPredicate(theButton, ACTIVATED);
  211.  
  212.     theLabel = GetVar(theButton, NAME);
  213.     if (theLabel)
  214.     {
  215.     label = GetString(theLabel);
  216.     }
  217.     else
  218.     {
  219.     label = (char *) NIL;
  220.     }
  221.  
  222.     theColor = GetVar(theButton, COLOR);
  223.     if (!theColor)
  224.     {
  225.     color = UIBACKGROUND;
  226.     }
  227.     else
  228.     {
  229.     color = GetPredicate(theButton, VALUE) ? GetInt(theColor) : UIBACKGROUND;
  230.     }
  231.  
  232.     if (!active)
  233.     {
  234.     BeginTranslucent();
  235.     DrawRaisedRect(left, right, bottom, top, hilight ? UIHIBACKGROUND : color);
  236.     EndTranslucent();
  237.     }
  238.     else
  239.     {
  240.     DrawRaisedRect(left, right, bottom, top, hilight ? UIHIBACKGROUND : color);
  241.     }
  242.  
  243.     /*Draw the stuff on the top here*/
  244.     method = GetMethod(theButton, DRAWCONTENTS);
  245.     if (method)
  246.     {
  247.     (*method)(theButton);
  248.     }
  249.  
  250.     return ObjTrue;
  251. #endif /* GRAPHICS */
  252. }
  253.  
  254. #ifdef PROTO
  255. ObjPtr NewDensityButton(int l, int r, int b, int t, char *name, int density)
  256. #else
  257. ObjPtr NewDensityButton(l, r, b, t, name, density)
  258. int l; int r; int b; int t; char *name; int density;
  259. #endif
  260. /*Creates a new density button*/
  261. {
  262.     ObjPtr retVal;
  263.  
  264.     retVal = NewObject(densityButtonClass, 0L);
  265.  
  266.     Set2DIntBounds(retVal, l, r, b, t);
  267.  
  268.     SetVar(retVal, VALUE, NewInt(0));
  269.     SetVar(retVal, HIGHLIGHTED, ObjFalse);
  270.     SetVar(retVal, NAME, NewString(name));
  271.     SetVar(retVal, ACTIVATED, ObjTrue);
  272.     SetVar(retVal, TICDENSITY, NewInt(density));
  273.     return retVal;
  274. }
  275.  
  276. #ifdef PROTO
  277. static int TimeToPixel(ObjPtr control, real time)
  278. #else
  279. static int TimeToPixel(control, time)
  280. ObjPtr control;
  281. real time;
  282. #endif
  283. /*Returns the x pixel for a specific time in a track control.
  284.   Check this against bounds of thing before drawing*/
  285. {
  286.     ObjPtr var, scrollbar;
  287.     real value, tpp;
  288.     int l, r, b, t, mid;
  289.     int leftWidth;
  290.     int pixWidth;
  291.  
  292.     Get2DIntBounds(control, &l, &r, &b, &t);
  293.     
  294.     var = GetIntVar("PixelToTime", control, LEFTSIDEWIDTH);
  295.     if (var)
  296.     {
  297.     leftWidth = GetInt(var);
  298.     }
  299.     else
  300.     {
  301.     leftWidth = 100;
  302.     }
  303.  
  304.  
  305.     l += leftWidth + 2 * TC_GAP + BARWIDTH + 1;
  306.     --r;
  307.  
  308.     pixWidth = r - l;
  309.  
  310.     MakeVar(control, TIMEPERPIXEL);
  311.     var = GetRealVar("PixelToTime", control, TIMEPERPIXEL);
  312.     if (var)
  313.     {
  314.     tpp = GetReal(var);
  315.     }
  316.     else
  317.     {
  318.     tpp = 0.1;
  319.     }
  320.  
  321.     mid = (l + r) / 2;
  322.  
  323.     scrollbar = GetVar(control, HSCROLL);
  324.     if (scrollbar)
  325.     {
  326.     var = GetValue(scrollbar);
  327.     if (var)
  328.     {
  329.         value = GetReal(var);
  330.     }
  331.     else
  332.     {
  333.         value = 0.0;
  334.     }
  335.     }
  336.     else
  337.     {
  338.     value = 0.0;
  339.     }
  340.  
  341.     return (time - value) / tpp + 0.5 + mid;
  342. }
  343.  
  344. static real PixelToTime(control, pixel)
  345. ObjPtr control;
  346. int pixel;
  347. /*Returns the time for a specific x pixel in a track control.
  348.   Check this against bounds of thing before drawing*/
  349. {
  350.     ObjPtr var, scrollbar;
  351.     real value, tpp;
  352.     int l, r, b, t, mid;
  353.     int leftWidth;
  354.     int pixWidth;
  355.  
  356.     Get2DIntBounds(control, &l, &r, &b, &t);
  357.     
  358.     var = GetIntVar("PixelToTime", control, LEFTSIDEWIDTH);
  359.     if (var)
  360.     {
  361.     leftWidth = GetInt(var);
  362.     }
  363.     else
  364.     {
  365.     leftWidth = 100;
  366.     }
  367.  
  368.  
  369.     l += leftWidth + 2 * TC_GAP + BARWIDTH + 1;
  370.     --r;
  371.  
  372.     pixWidth = r - l;
  373.  
  374.     MakeVar(control, TIMEPERPIXEL);
  375.     var = GetRealVar("PixelToTime", control, TIMEPERPIXEL);
  376.     if (var)
  377.     {
  378.     tpp = GetReal(var);
  379.     }
  380.     else
  381.     {
  382.     tpp = 0.1;
  383.     }
  384.  
  385.     mid = (l + r) / 2;
  386.  
  387.     scrollbar = GetVar(control, HSCROLL);
  388.     if (scrollbar)
  389.     {
  390.     var = GetValue(scrollbar);
  391.     if (var)
  392.     {
  393.         value = GetReal(var);
  394.     }
  395.     else
  396.     {
  397.         value = 0.0;
  398.     }
  399.     }
  400.     else
  401.     {
  402.     value = 0.0;
  403.     }
  404.  
  405.     return (pixel - mid) * tpp + value;
  406. }
  407.  
  408. static ObjPtr ChangeTrackControlVScroll(scrollbar)
  409. ObjPtr scrollbar;
  410. /*Changes in response to a vertical scrollbar*/
  411. {
  412.     ObjPtr repObj;
  413.     int l, r, b, t, dummy;
  414.  
  415.     repObj = GetVar(scrollbar, REPOBJ);
  416.     if (repObj)
  417.     {
  418.     Get2DIntBounds(repObj, &l, &r, &dummy, &dummy);
  419.     Get2DIntBounds(scrollbar, &dummy, &dummy, &b, &t);
  420.     ImInvalidBounds(repObj, l + 1, r - 1, b + 1, t - 1);
  421.     }
  422.     return ObjTrue;
  423. }
  424.  
  425. static ObjPtr ChangeTrackControlHScroll(scrollbar)
  426. ObjPtr scrollbar;
  427. /*Changes in response to a horizontal scrollbar*/
  428. {
  429.     ObjPtr repObj;
  430.     int l, r, b, t, dummy;
  431.  
  432.     repObj = GetVar(scrollbar, REPOBJ);
  433.     if (repObj)
  434.     {
  435.     Get2DIntBounds(scrollbar, &l, &r, &dummy, &dummy);
  436.     Get2DIntBounds(repObj, &dummy, &dummy, &b, &t);
  437.     ImInvalidBounds(repObj, l + 1, r - 1, b + 1, t - 1);
  438.     }
  439.     return ObjTrue;
  440. }
  441.  
  442. static ObjPtr MakeDenser(button)
  443. ObjPtr button;
  444. /*Makes a track control denser*/
  445. {
  446.     ObjPtr repObj, var;
  447.  
  448.     repObj = GetObjectVar("MakeDenser", button, REPOBJ);
  449.     if (!repObj)
  450.     {
  451.     return ObjFalse;
  452.     }
  453.  
  454.     MakeVar(repObj, TIMEPERPIXEL);
  455.     var = GetVar(repObj, TIMEPERPIXEL);
  456.     if (var)
  457.     {
  458.     SaveForUndo(repObj);
  459.     SetVar(repObj, TIMEPERPIXEL, NewReal(GetReal(var) * DENSITYFACTOR));
  460.     RecalcScroll(repObj);
  461.     return ObjTrue;
  462.     }
  463.  
  464.     return ObjFalse;
  465. }
  466.  
  467. static ObjPtr MakeSparser(button)
  468. ObjPtr button;
  469. /*Makes a track control sparser*/
  470. {
  471.     ObjPtr repObj, var;
  472.  
  473.     repObj = GetObjectVar("MakeSparser", button, REPOBJ);
  474.     if (!repObj)
  475.     {
  476.     return ObjFalse;
  477.     }
  478.  
  479.     MakeVar(repObj, TIMEPERPIXEL);
  480.     var = GetVar(repObj, TIMEPERPIXEL);
  481.     if (var)
  482.     {
  483.     SaveForUndo(repObj);
  484.     SetVar(repObj, TIMEPERPIXEL, NewReal(GetReal(var) / DENSITYFACTOR));
  485.     RecalcScroll(repObj);
  486.     return ObjTrue;
  487.     }
  488.  
  489.     return ObjFalse;
  490. }
  491.  
  492. #ifdef PROTO
  493. ObjPtr NewTrackControl(int l, int r, int b, int t, char *name, real low, real high)
  494. #else
  495. ObjPtr NewTrackControl(l, r, b, t, name, low, high)
  496. int l, r, b, t;
  497. char *name;
  498. real low, high;
  499. #endif
  500. /*Returns a new track control*/
  501. {
  502.     ObjPtr retVal, scrollbar, readout, button;
  503.     int leftWidth;
  504.     real min, max, portionShown;
  505.     ObjPtr var;
  506.  
  507.     retVal = NewObject(trackControlClass, 0L);
  508.     if (!retVal)
  509.     {
  510.     return NULLOBJ;
  511.     }
  512.     Set2DIntBounds(retVal, l, r, b, t);
  513.     SetVar(retVal, NAME, NewString(name));
  514.  
  515.     /*Find out parameters of the control*/
  516.     var = GetIntVar("NewTrackControl", retVal, LEFTSIDEWIDTH);
  517.     if (var)
  518.     {
  519.     leftWidth = GetInt(var);
  520.     }
  521.     else
  522.     {
  523.     leftWidth = 100;
  524.     }
  525.  
  526.     /*Create the scroll bars*/
  527. #ifdef SCROLLINMIDDLE
  528.     scrollbar = NewScrollbar(l + leftWidth + TC_GAP, l + leftWidth + TC_GAP + BARWIDTH,
  529.                  b + BARWIDTH + TC_GAP,
  530.                  t - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP,
  531.                  "Track Scroll");
  532. #else
  533.     scrollbar = NewScrollbar(l, l + BARWIDTH,
  534.                  b + BARWIDTH + TC_GAP,
  535.                  t - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP,
  536.                  "Track Scroll");
  537. #endif
  538.     SetVar(scrollbar, PARENT, retVal);
  539.     SetVar(scrollbar, REPOBJ, retVal);
  540.     SetMethod(scrollbar, CHANGEDVALUE, ChangeTrackControlVScroll);
  541.     SetVar(retVal, VSCROLL, scrollbar);
  542.  
  543.     scrollbar = NewScrollbar(l + leftWidth + 2 * TC_GAP + BARWIDTH, r,
  544.                  b,
  545.                  b + BARWIDTH,
  546.                  "Time Scroll");
  547.     SetVar(scrollbar, PARENT, retVal);
  548.     SetVar(scrollbar, REPOBJ, retVal);
  549.     SetMethod(scrollbar, CHANGEDVALUE, ChangeTrackControlHScroll);
  550.     SetVar(retVal, HSCROLL, scrollbar);
  551.  
  552.     /*Create the time readout*/
  553.     readout = NewTextBox(l + TC_LEFTLABEL, l + leftWidth + TC_GAP + BARWIDTH,
  554.     t - TC_TIMEHEIGHT + TC_GAP, t,
  555.     EDITABLE + WITH_PIT + ONE_LINE, "Time Readout", "0.0");
  556. /*
  557.     SetMethod(readout, CHANGEDVALUE, ChangeTrackTimeReadout);
  558. */
  559.     SetVar(readout, PARENT, retVal);
  560.     SetTextAlign(readout, RIGHTALIGN);
  561.     SetVar(retVal, READOUT, readout);
  562.  
  563.     /*Create the frame readout*/
  564.     readout = NewTextBox(l + TC_LEFTLABEL, l + leftWidth + TC_GAP + BARWIDTH,
  565.     t - TC_TIMEHEIGHT - TC_CURHEIGHT, t - TC_TIMEHEIGHT,
  566.     EDITABLE + WITH_PIT + ONE_LINE, "Frame Readout", "0");
  567. /*
  568.     SetMethod(readout, CHANGEDVALUE, ChangeTrackFrameReadout);
  569. */
  570.     SetVar(readout, PARENT, retVal);
  571.     SetTextAlign(readout, RIGHTALIGN);
  572.     SetVar(retVal, READOUT2, readout);
  573.  
  574.     SetVar(retVal, LOVALUE, NewReal(low));
  575.     SetVar(retVal, HIVALUE, NewReal(high));
  576.  
  577.     SetVar(retVal, TIMEPERPIXEL, NewReal(TC_TPP));
  578.  
  579.     portionShown = (r - (l + leftWidth + TC_GAP * 2 + BARWIDTH) - 2) * TC_TPP;
  580.     min = low + portionShown * (0.5 - TC_MARGIN);
  581.     max = high - portionShown * (0.5 - TC_MARGIN);
  582.     if (min > max)
  583.     {
  584.         min = (min + max) * 0.5;
  585.         max = min;
  586.     }
  587.     SetSliderValue(scrollbar, min);
  588.     SetSliderRange(scrollbar, min, max, portionShown / 10.0);
  589.  
  590.     SetVar(retVal, FRAMERATE, NewReal(30.0));
  591.     SetVar(retVal, VALUE, NewReal(low));
  592.  
  593.     /*Now make buttons*/
  594.     button = NewDensityButton(l + leftWidth - TC_DBWIDTH,
  595.         l + leftWidth,
  596.         b, b + BARWIDTH, "Expand", 6);
  597.     SetVar(button, PARENT, retVal);
  598.     SetVar(retVal, SPARSERBUTTON, button);
  599.     SetVar(button, REPOBJ, retVal);
  600.     SetMethod(button, CHANGEDVALUE, MakeSparser);
  601.  
  602.     button = NewDensityButton(l + leftWidth - TC_DBWIDTH * 2 - TC_GAP,
  603.         l + BARWIDTH  + leftWidth - BARWIDTH - TC_DBWIDTH - TC_GAP,
  604.         b, b + BARWIDTH, "Contract", 3);
  605.     SetVar(button, PARENT, retVal);
  606.     SetVar(retVal, DENSERBUTTON, button);
  607.     SetVar(button, REPOBJ, retVal);
  608.     SetMethod(button, CHANGEDVALUE, MakeDenser);
  609.  
  610.     return retVal;
  611. }
  612.  
  613. ObjPtr DrawTrackControl(object)
  614. ObjPtr object;
  615. /*Draws a track control*/
  616. {
  617. #ifdef GRAPHICS
  618.     ObjPtr hScroll, vScroll, readout, var, timeVar, button;
  619.     int left, right, bottom, top, timePix, x, y, height;
  620.     long k, lowestTrack;
  621.     int shownHeight;
  622.     real value;
  623.     long downOffset;
  624.     long line;
  625.     int leftWidth;
  626.     ObjPtr repObj;
  627.     ObjPtr tracks;
  628.     ObjPtr *elements;
  629.     real loValue, hiValue;
  630.  
  631.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  632.  
  633.     if (IsDrawingRestricted(left, right, bottom, top))
  634.     {
  635.     return ObjTrue;
  636.     }
  637.  
  638.     /*Get the value*/
  639.     var = GetRealVar("DrawTrackControl", object, VALUE);
  640.     if (var)
  641.     {
  642.     value = GetReal(var);
  643.     }
  644.     else
  645.     {
  646.     value = 0.0;
  647.     }
  648.  
  649.     /*Get the low and high values*/
  650.     var = GetRealVar("DrawTrackControl", object, LOVALUE);
  651.     if (var)
  652.     {
  653.     loValue = GetReal(var);
  654.     }
  655.     else
  656.     {
  657.     loValue = 0.0;
  658.     }
  659.     var = GetRealVar("DrawTrackControl", object, HIVALUE);
  660.     if (var)
  661.     {
  662.     hiValue = GetReal(var);
  663.     }
  664.     else
  665.     {
  666.     hiValue = 0.0;
  667.     }
  668.  
  669.     /*Find out parameters of the control*/
  670.     var = GetIntVar("DrawTrackControl", object, LEFTSIDEWIDTH);
  671.     if (var)
  672.     {
  673.     leftWidth = GetInt(var);
  674.     }
  675.     else
  676.     {
  677.     leftWidth = 100;
  678.     }
  679.  
  680.     /*Get the repObj*/
  681.     repObj = GetVar(object, REPOBJ);
  682.  
  683.     if (repObj)
  684.     {
  685.     tracks = GetVar(repObj, TRACKS);
  686.     }
  687.     else
  688.     {
  689.     tracks = NULLOBJ;
  690.     }
  691.  
  692.     SetUIFont(TCFONT);
  693.  
  694.     /*Draw the scroll bars*/
  695.     hScroll = GetVar(object, HSCROLL);
  696.     if (hScroll)
  697.     {
  698.     DrawObject(hScroll);
  699.     }
  700.  
  701.     vScroll = GetVar(object, VSCROLL);
  702.     if (vScroll)
  703.     {
  704.     DrawObject(vScroll);
  705.     }
  706.  
  707.     /*Draw the readouts*/
  708.     readout = GetVar(object, READOUT);
  709.     if (readout)
  710.     {
  711.     DrawObject(readout);
  712.     }
  713.  
  714.     readout = GetVar(object, READOUT2);
  715.     if (readout)
  716.     {
  717.     DrawObject(readout);
  718.     }
  719.  
  720.     /*Draw the buttons*/
  721.     button = GetVar(object, DENSERBUTTON);
  722.     if (button)
  723.     {
  724.     DrawObject(button);
  725.     }
  726.  
  727.     button = GetVar(object, SPARSERBUTTON);
  728.     if (button)
  729.     {
  730.     DrawObject(button);
  731.     }
  732.  
  733.     /*Draw the arrows control*/
  734.     x = left + leftWidth + TC_GAP + BARWIDTH / 2;
  735.     y = bottom + BARWIDTH / 2;
  736.     FillUITri(x - TC_ARROWGAP / 2, y + TC_ARROWSIZE / 2,
  737.           x - TC_ARROWGAP / 2 - TC_ARROWSIZE / 2, y,
  738.           x - TC_ARROWGAP / 2, y - TC_ARROWSIZE / 2, UIBLACK);
  739.     FillUITri(x + TC_ARROWGAP / 2, y - TC_ARROWSIZE / 2,
  740.           x + TC_ARROWGAP / 2 + TC_ARROWSIZE / 2, y,
  741.           x + TC_ARROWGAP / 2, y + TC_ARROWSIZE / 2, UIBLACK);
  742.     FillUIRect(x - TC_VLINEWIDTH / 2, x + TC_VLINEWIDTH / 2,
  743.            y - TC_VLINEHEIGHT / 2, y + TC_VLINEHEIGHT / 2, UIBLACK);
  744.  
  745.     /*Draw the track names box*/
  746. #ifdef SCROLLINMIDDLE
  747.     FillUIRect(left + 1, left + leftWidth - 1, bottom + TC_GAP + BARWIDTH + 1, top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1, UIGRAY62);
  748. #else
  749.     FillUIRect(left + BARWIDTH + TC_GAP + 1, left + BARWIDTH + TC_GAP + leftWidth - 1, bottom + TC_GAP + BARWIDTH + 1, top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1, UIGRAY62);
  750. #endif
  751.  
  752.     /*Get downOffset from vertical scroll bar*/
  753.     if (vScroll)
  754.     {
  755.     downOffset = (long) GetReal(GetValue(vScroll));
  756.     }
  757.     else
  758.     {
  759.     downOffset = 0;
  760.     }
  761.  
  762.     if (tracks)
  763.     {
  764.     /*Draw the contents of the tracks*/
  765.  
  766.     elements = ELEMENTS(tracks);
  767.  
  768.     /*Search for a place to begin*/
  769.     y = -downOffset;
  770.  
  771.     for (k = 0; k < DIMS(tracks)[0]; ++k)
  772.     {
  773.         MakeVar(elements[k], TRACKHEIGHT);
  774.         var = GetVar(elements[k], TRACKHEIGHT);
  775.         if (var)
  776.         {
  777.         height = GetInt(var);
  778.         if ((y - height) < 0) break;
  779.         y -= height;
  780.         }
  781.     }
  782.  
  783.     if (k < DIMS(tracks)[0])
  784.     {
  785.         /*There's something to print*/
  786.         FuncTyp method;
  787.  
  788.         lowestTrack = k;
  789.  
  790.         shownHeight = top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 
  791.           (bottom + TC_GAP + BARWIDTH) - 2;
  792.  
  793. #ifdef SCROLLINMIDDLE
  794.         SetClipRect(left + 1, left + leftWidth - 1, bottom + TC_GAP + BARWIDTH + 1, top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1);
  795. #else
  796.         SetClipRect(left + BARWIDTH + TC_GAP + 1, left + BARWIDTH + TC_GAP + leftWidth - 1, bottom + TC_GAP + BARWIDTH + 1, top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1);
  797. #endif
  798.         for (k = lowestTrack; (k < DIMS(tracks)[0]) && (y > -shownHeight); ++k)
  799.         {
  800.         MakeVar(elements[k], TRACKHEIGHT);
  801.         var = GetVar(elements[k], TRACKHEIGHT);
  802.         if (var)
  803.         {
  804.             height = GetInt(var);
  805.             method = GetMethod(elements[k], DRAWNAME);
  806.             if (method)
  807.             {
  808. #ifdef SCROLLINMIDDLE
  809.             (*method)(elements[k],
  810.                 left + 1, left + leftWidth - 1,
  811.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y - height,
  812.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y);
  813. #else
  814.             (*method)(elements[k],
  815.                 left + BARWIDTH + TC_GAP + 1, left + BARWIDTH + TC_GAP + leftWidth - 1,
  816.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y - height,
  817.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y);
  818. #endif
  819.             }
  820.  
  821.             y -= height;
  822.         }
  823.         }
  824.         RestoreClipRect();
  825.     }
  826.  
  827.     }
  828.  
  829.     /*Draw the timeline box*/
  830.     FillUIRect(    left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  831.         right - 1,
  832.         top - TC_TIMEHEIGHT,
  833.         top - 1,
  834.         UIGRAY62);
  835.  
  836.     FillUIRect(    left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  837.         right - 1,
  838.         top - TC_TIMEHEIGHT - CEDGE,
  839.         top - TC_TIMEHEIGHT,
  840.         UIBOTTOMEDGE);
  841.     FillUIRect(    left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  842.         right - 1,
  843.         top - TC_TIMEHEIGHT - TC_CURHEIGHT + CEDGE,
  844.         top - TC_TIMEHEIGHT - CEDGE,
  845.         timeVar ? UIPGREEN : UIGRAY50);
  846.  
  847.     FillUIRect(left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  848.         right - 1,
  849.         top - TC_TIMEHEIGHT - TC_CURHEIGHT,
  850.         top - TC_TIMEHEIGHT - TC_CURHEIGHT + CEDGE,
  851.         UITOPEDGE);
  852.  
  853.     FillUIRect(    left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  854.         right - 1,
  855.         bottom + TC_GAP + BARWIDTH + 1,
  856.         top - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP,
  857.         UIGRAY62);
  858.  
  859.     FillUIRect(    left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  860.         right - 1,
  861.         top - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP,
  862.         top - TC_TIMEHEIGHT - TC_CURHEIGHT,
  863.         UIGRAY62);
  864.  
  865.     /*Draw the contents of the timeline box*/
  866.     if (hScroll)
  867.     {
  868.     ObjPtr var;
  869.     char timeStr[256];
  870.     int format;
  871.     real timePerPixel, timeAtPixel;
  872.     double majorWidth, minorWidth;
  873.     double frameWidth;
  874.     int curPixel;
  875.     int timePixel;
  876.     real curTime;
  877.     int k;
  878.     int pixWidth;
  879.     real portionShown;
  880.  
  881.     MakeVar(object, TIMEFORMAT);
  882.     var = GetVar(object, TIMEFORMAT);
  883.     if (var)
  884.     {
  885.         format = GetInt(var);
  886.     }
  887.     else
  888.     {
  889.         format = TF_SECONDS + TF_SUBSECONDS;
  890.     }
  891.  
  892.     /*Draw the time numbers*/
  893.  
  894.     pixWidth = (right - 1) - (left + leftWidth + 2 * TC_GAP + BARWIDTH + 1);
  895.  
  896.     MakeVar(object, TIMEPERPIXEL);
  897.     var = GetRealVar("PixelToTime", object, TIMEPERPIXEL);
  898.     if (var)
  899.     {
  900.         portionShown = GetReal(var) * pixWidth;
  901.     }
  902.     else
  903.     {
  904.         portionShown = 60.0;
  905.     }
  906.     timePerPixel = portionShown / ((real) pixWidth);
  907.  
  908.     /*Get the step and tics*/
  909.     
  910.     CalcGeneralSteps(portionShown, pixWidth, TC_MAJORSTEP, TC_MINORSTEP,
  911.         sizeof(timeSteps) / sizeof(real), timeSteps, 
  912.         &majorWidth, &minorWidth);
  913.  
  914.     /*Get a pixel that's way off the left*/
  915.     timePixel = left + leftWidth + 2 * TC_GAP + BARWIDTH + 1 - TCMAXTIMEWIDTH;
  916.     timeAtPixel = PixelToTime(object, timePixel);
  917.     if (timeAtPixel < loValue - minorWidth * 0.5) timeAtPixel = loValue;
  918.     timeAtPixel = floor(timeAtPixel / majorWidth) * majorWidth;
  919.     timePixel = TimeToPixel(object, timeAtPixel);
  920.  
  921.     /*Write out the times*/
  922.     SetClipRect(left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  923.             right - 1,
  924.             bottom + 1,
  925.             top - 1);
  926.     SetUIFont(TCTIMEFONT);
  927.     SetUIColor(UIBLACK);
  928.  
  929.     curPixel = timePixel;
  930.     curTime = timeAtPixel;
  931.     do
  932.     {
  933.         if (format)
  934.         {
  935.         PrintTime(timeStr, curTime, format);
  936.         }
  937.         else
  938.         {
  939.         sprintf(timeStr, "%g", curTime);
  940.         }
  941.         if (timeStr[0] == '-') strcat(timeStr, " ");
  942.         DrawAString(CENTERALIGN, curPixel, 
  943.                top - TC_TIMEHEIGHT + 1 + TC_TIMEBOFF,
  944.                timeStr);
  945.         DrawUILine(curPixel, top - TC_TIMEHEIGHT + TC_TIMEBOFF - 1,
  946.                curPixel, top - TC_TIMEHEIGHT, UIBLACK);
  947. #if 0
  948.         DrawUILine(curPixel,
  949.             bottom + BARWIDTH + TC_GAP + 1, curPixel,
  950.             top - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP,
  951.             UIBLACK);
  952. #endif
  953.         curTime += majorWidth;
  954.         curTime = floor(curTime / majorWidth + 0.5) * majorWidth;
  955.         curPixel = TimeToPixel(object, curTime);
  956.     }
  957.     while (curPixel < right + TCMAXTIMEWIDTH &&
  958.            curTime < hiValue + minorWidth / 2);
  959.  
  960.     /*Now do minor tics*/
  961.     curPixel = timePixel;
  962.     curTime = timeAtPixel;
  963.     do
  964.     {
  965.         DrawUILine(curPixel, top - TC_TIMEHEIGHT + TC_TIMEBOFF / 2 - 1,
  966.                curPixel, top - TC_TIMEHEIGHT, UIBLACK);
  967.         curTime += minorWidth;
  968.         curTime = floor(curTime / minorWidth + 0.5) * minorWidth;
  969.         curPixel = TimeToPixel(object, curTime);
  970.     }
  971.     while (curPixel < right &&
  972.            curTime < hiValue + minorWidth / 2);
  973.  
  974.     /*Now do frame lines*/
  975.     MakeVar(object, FRAMERATE);
  976.     var = GetVar(object, FRAMERATE);
  977.     if (var)
  978.     {
  979.         frameWidth = 1.0 / GetReal(var);
  980.  
  981.         /*Get a pixel that's way off the left*/
  982.         timePixel = left + leftWidth + 2 * TC_GAP + BARWIDTH;
  983.         timeAtPixel = PixelToTime(object, timePixel);
  984.         timeAtPixel = floor(timeAtPixel / frameWidth) * frameWidth;
  985.         if (timeAtPixel < loValue) timeAtPixel = loValue;
  986.         timePixel = TimeToPixel(object, timeAtPixel);
  987.  
  988.         /*Test to see if it's worth doing*/
  989.         if (frameWidth / timePerPixel > 6.0)
  990.         {
  991.         /*Now do minor tics*/
  992.         curPixel = timePixel;
  993.         curTime = timeAtPixel;
  994.         do
  995.         {
  996.             DrawUILine(curPixel,
  997.             bottom + BARWIDTH + TC_GAP + 1, curPixel,
  998.             top - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP - 1,
  999.             UIGRAY50);
  1000.             curTime += frameWidth;
  1001.             curTime = floor(curTime / frameWidth + 0.5) * frameWidth;
  1002.             curPixel = TimeToPixel(object, curTime);
  1003.         }
  1004.         while (curPixel < right &&
  1005.                 curTime < hiValue - frameWidth / 2);
  1006.         }
  1007.     }
  1008.  
  1009.     RestoreClipRect();
  1010.  
  1011.     /*Draw the tracks*/
  1012.     if (tracks)
  1013.     {
  1014.         /*Draw the contents of the tracks*/
  1015.  
  1016.         elements = ELEMENTS(tracks);
  1017.  
  1018.         /*Search for a place to begin*/
  1019.         y = -downOffset;
  1020.  
  1021.         for (k = 0; k < DIMS(tracks)[0]; ++k)
  1022.         {
  1023.         MakeVar(elements[k], TRACKHEIGHT);
  1024.         var = GetVar(elements[k], TRACKHEIGHT);
  1025.         if (var)
  1026.         {
  1027.             height = GetInt(var);
  1028.             if ((y - height) < 0) break;
  1029.             y -= height;
  1030.         }
  1031.         }
  1032.  
  1033.         if (k < DIMS(tracks)[0])
  1034.         {
  1035.         /*There's something to draw*/
  1036.         FuncTyp method;
  1037.         real minTime, maxTime;
  1038.  
  1039.         minTime = PixelToTime(object, left + BARWIDTH + 2 * TC_GAP + leftWidth + 1);
  1040.         maxTime = PixelToTime(object, right - 1);
  1041.  
  1042.         lowestTrack = k;
  1043.  
  1044.         shownHeight = top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 
  1045.           (bottom + TC_GAP + BARWIDTH) - 2;
  1046.         SetClipRect(left + BARWIDTH + 2 * TC_GAP + leftWidth + 1,
  1047.                 right - 1,
  1048.                 bottom + TC_GAP + BARWIDTH + 1,
  1049.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1);
  1050.         for (k = lowestTrack; (k < DIMS(tracks)[0]) && (y > -shownHeight); ++k)
  1051.         {
  1052.             MakeVar(elements[k], TRACKHEIGHT);
  1053.             var = GetVar(elements[k], TRACKHEIGHT);
  1054.             if (var)
  1055.             {
  1056.             height = GetInt(var);
  1057.             method = GetMethod(elements[k], DRAWTRACK);
  1058.             if (method)
  1059.             {
  1060.                 (*method)(elements[k],
  1061.                 left + BARWIDTH + 2 * TC_GAP + leftWidth + 1,
  1062.                 right - 1,
  1063.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y - height,
  1064.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y,
  1065.                 minTime, maxTime);
  1066.             }
  1067.  
  1068.             y -= height;
  1069.             }
  1070.         }
  1071.         RestoreClipRect();
  1072.         }
  1073.     }
  1074.  
  1075. #if 0
  1076.     /*Draw the time lines*/
  1077.     line = (-downOffset / TC_CELLHEIGHT);
  1078.     if (line < DIMS(datasets)[0])
  1079.     {
  1080.         /*It's worth printing*/
  1081.         int midy;
  1082.         ObjPtr element;
  1083.         SetClipRect(left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  1084.             right - 1,
  1085.             bottom + TC_GAP + BARWIDTH + 1,
  1086.             top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1);
  1087.         midy = top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 - (line + 1) * TC_CELLHEIGHT + TCLINEBOFF - downOffset;
  1088.         SetUIColor(UIBLACK);
  1089.         while (line < DIMS(datasets)[0] &&
  1090.            midy > bottom + TC_GAP + BARWIDTH + 1 - TC_CELLHEIGHT)
  1091.         {
  1092.         /*Print out the timeline of the object*/
  1093.         Bool interpolateP;
  1094.  
  1095.         ObjPtr timeSteps;
  1096.         element = GetObjectElement(datasets, &line);
  1097.         MakeVar(element, TIMESTEPS);
  1098.         timeSteps = GetVar(element, TIMESTEPS);
  1099.         MakeVar(element, INTERPOLATEP);
  1100.         interpolateP = GetPredicate(element, INTERPOLATEP);
  1101.  
  1102.         if (timeSteps)
  1103.         {
  1104.             /*Object with time steps.  Find the first*/
  1105.             int pixel;
  1106.             long ts1, ts2;
  1107.             real leftTime, rightTime;
  1108.  
  1109.             /*Get a pixel that's clear off the left side*/
  1110.             pixel = left;
  1111.             leftTime = PixelToTime(object, pixel);
  1112.  
  1113.             /*Get its index*/
  1114.             ts1 = SearchReal(timeSteps, leftTime);
  1115.             if (ts1 > 0)
  1116.             {
  1117.             --ts1;
  1118.             }
  1119.             {
  1120.             /*There's a chance it can be drawn.  Get a pixel 
  1121.               clear off the right*/
  1122.             pixel = right + TCSAMPLESIZE;
  1123.             rightTime = PixelToTime(object, pixel);
  1124.  
  1125.             /*Get its index*/
  1126.             ts2 = SearchReal(timeSteps, rightTime);
  1127.             if (ts2 >= DIMS(timeSteps)[0])
  1128.             {
  1129.                 --ts2;
  1130.             }
  1131.             if (ts2 >= ts1)
  1132.             {
  1133.                 /*DrawIt*/
  1134.                 real *timeElements;
  1135.                 long k;
  1136.                 long coords[2];
  1137.                 int p1, p2;
  1138.  
  1139.                 timeElements = (real *) ELEMENTS(timeSteps);
  1140.                 element = GetObjectElement(datasets, &line);
  1141.  
  1142.                 p1 = TimeToPixel(object, timeElements[ts1]);
  1143.                 for (k = ts1 + 1; k <= ts2; ++k)
  1144.                 {
  1145.                 p2 = TimeToPixel(object, timeElements[k]);
  1146.                 if (!interpolateP)
  1147.                 {
  1148.                     DrawUILine((p1 + p2) / 2, midy + TCMIDTICHEIGHT,
  1149.                        (p1 + p2) / 2, midy - TCMIDTICHEIGHT - 1,
  1150.                        UIBLACK);
  1151.                     DrawUILine((p1 + p2) / 2 + 1, midy + TCMIDTICHEIGHT,
  1152.                        (p1 + p2) / 2 + 1, midy - TCMIDTICHEIGHT - 1,
  1153.                        UIBLACK);
  1154.                     setlinestyle(DASHEDLINE);
  1155.                 }
  1156.                 DrawUILine(p1, midy,
  1157.                            p2, midy,
  1158.                            UIBLACK);
  1159.                 DrawUILine(p1, midy - 1,
  1160.                            p2, midy - 1,
  1161.                            UIBLACK);
  1162.                 if (!interpolateP)
  1163.                 {
  1164.                     setlinestyle(SOLIDLINE);
  1165.                 }
  1166.                 p1 = p2;
  1167.                 }
  1168.                 for (k = ts1; k <= ts2; ++k)
  1169.                 {
  1170.                 pixel = TimeToPixel(object, timeElements[k]);
  1171.                 SetUIColor(TCSAMPLECOLOR);
  1172.                 FillRealQuad((real) pixel, (real) midy + TCSAMPLESIZE / 2,
  1173.                     (real) pixel - TCSAMPLESIZE / 2, (real) midy,
  1174.                     (real) pixel, (real) midy - TCSAMPLESIZE / 2,
  1175.                     (real) pixel + TCSAMPLESIZE / 2, (real) midy);
  1176.                 }
  1177.             }
  1178.             }
  1179.         }
  1180.         else
  1181.         {
  1182.             /*Eternal object*/
  1183.             SetLineWidth(2);
  1184.             DrawUILine(left + leftWidth + 2 * TC_GAP + BARWIDTH + 1, midy,
  1185.                    right - 1, midy, TCSAMPLECOLOR);
  1186.             SetLineWidth(1);
  1187.         }
  1188.         midy -= TC_CELLHEIGHT;
  1189.         ++line;
  1190.         }
  1191.         RestoreClipRect();
  1192.     }
  1193. #endif
  1194.     }
  1195.  
  1196.     if (timeVar == NULLOBJ)
  1197.     {
  1198.     FillUIGauzeRect(left + leftWidth + 2 * TC_GAP + BARWIDTH + 1,
  1199.             right - 1,
  1200.             top - TC_TIMEHEIGHT - TC_CURHEIGHT,
  1201.             top - TC_TIMEHEIGHT,
  1202.             UIBACKGROUND);
  1203.     }
  1204.  
  1205.     if (timeVar)
  1206.     {
  1207.     timePix = TimeToPixel(object, value);
  1208.     if (timePix > left + leftWidth + 2 * TC_GAP + BARWIDTH - TCCURWIDTH &&
  1209.         timePix < right + TCCURWIDTH)
  1210.     {
  1211.         /*Draw the time cursor*/
  1212.         SetClipRect(left + leftWidth + 2 * TC_GAP + BARWIDTH + 1, right - 1, bottom + TC_GAP + BARWIDTH + 1, top - 1);
  1213.         DrawVCursor(timePix, top - 1 - TC_TIMEHEIGHT + TC_TIMEBOFF, bottom + TC_GAP + BARWIDTH + 1);
  1214.         DrawRaisedRect(timePix - TCCURWIDTH / 2, timePix + TCCURWIDTH / 2,
  1215.             top - TC_TIMEHEIGHT - TC_CURHEIGHT + 1 + CEDGE, top - TC_TIMEHEIGHT - 1 - CEDGE,
  1216.             GetPredicate(object, HIGHLIGHTED) ? UIHIBACKGROUND : UIBACKGROUND);
  1217.         RestoreClipRect();
  1218.     }
  1219.     }
  1220.  
  1221.     /*Draw the frames of the boxes*/
  1222. #ifdef SCROLLINMIDDLE
  1223.     FrameUIRect(left, left + leftWidth, bottom + TC_GAP + BARWIDTH, top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIBLACK);
  1224. #else
  1225.     FrameUIRect(left + BARWIDTH + TC_GAP, left + BARWIDTH + TC_GAP + leftWidth, bottom + TC_GAP + BARWIDTH, top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIBLACK);
  1226. #endif
  1227.  
  1228.     FrameUIRect(left + leftWidth + 2 * TC_GAP + BARWIDTH,
  1229.         right,
  1230.         bottom + TC_GAP + BARWIDTH,
  1231.         top, UIBLACK);
  1232.     DrawUILine(    left + leftWidth + 2 * TC_GAP + BARWIDTH,
  1233.         top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1,
  1234.         right - 1,
  1235.         top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1,
  1236.         UIBLACK);
  1237.  
  1238.     /*Draw "Time:" and "Frame:"*/
  1239.     SetUIColor(UIBLACK);
  1240.     SetUIFont(TCFONT);
  1241.     DrawAString(LEFTALIGN, left, top - TC_TIMEHEIGHT + TC_GAP + TC_LABELUP, "Time:");
  1242.     DrawAString(LEFTALIGN, left, top - TC_TIMEHEIGHT - TC_CURHEIGHT + TC_LABELUP, "Frame:");
  1243. #endif
  1244.     return ObjTrue;
  1245. }
  1246.  
  1247. ObjPtr ReshapeTrackControl(object, ol, or, ob, ot, left, right, bottom, top)
  1248. ObjPtr object;
  1249. int ol, or, ob, ot, left, right, bottom, top;
  1250. /*Reshapes a track control*/
  1251. {
  1252.     ObjPtr var;
  1253.     int leftWidth, l, r, b, t, width, height;
  1254.     int stickiness;
  1255.     real wr, hr;            /*Width and height ratios*/
  1256.  
  1257.     wr = ((real) (right - left)) / ((real) (or - ol));
  1258.     hr = ((real) (top - bottom)) / ((real) (ot - ob));
  1259.  
  1260.     /*Find out parameters of the control*/
  1261.     var = GetIntVar("DrawTrackControl", object, LEFTSIDEWIDTH);
  1262.     if (var)
  1263.     {
  1264.     leftWidth = GetInt(var);
  1265.     }
  1266.     else
  1267.     {
  1268.     leftWidth = 100;
  1269.     }
  1270.  
  1271.     /*Get the current bounds*/
  1272.     Get2DIntBounds(object, &l, &r, &b, &t);
  1273.     width = r - l;
  1274.     height = t - b;
  1275.  
  1276.     /*Get the object's stickiness*/
  1277.     var = GetVar(object, STICKINESS);
  1278.     if (var && IsInt(var))
  1279.     {
  1280.     stickiness = GetInt(var);
  1281.     }
  1282.     else
  1283.     {
  1284.     stickiness = 0;
  1285.     }
  1286.  
  1287.     if ((stickiness & STICKYLEFT) || (stickiness & FLOATINGLEFT))
  1288.     {
  1289.     if (stickiness & FLOATINGLEFT)
  1290.     {
  1291.         l = (l - ol) * wr + left;
  1292.     }
  1293.     else
  1294.     {
  1295.         l += left - ol;
  1296.     }
  1297.     if (!((stickiness & STICKYRIGHT) || (stickiness & FLOATINGRIGHT)))
  1298.     {
  1299.         r = l + width;
  1300.     }
  1301.     }
  1302.  
  1303.     if ((stickiness & STICKYRIGHT) || (stickiness & FLOATINGRIGHT))
  1304.     {
  1305.     if (stickiness & FLOATINGRIGHT)
  1306.     {
  1307.         r = (r - ol) * wr + left;
  1308.     }
  1309.     else
  1310.     {
  1311.         r += right - or;
  1312.     }
  1313.     if (!((stickiness & STICKYLEFT) || (stickiness & FLOATINGLEFT)))
  1314.     {
  1315.         l = r - width;
  1316.     }
  1317.     }
  1318.  
  1319.     if ((stickiness & STICKYBOTTOM) || (stickiness & FLOATINGBOTTOM))
  1320.     {
  1321.     if (stickiness & FLOATINGBOTTOM)
  1322.     {
  1323.         b = (b - ob) * hr + bottom;
  1324.     }
  1325.     else
  1326.     {
  1327.         b += bottom - ob;
  1328.     }
  1329.     if (!((stickiness & STICKYTOP) || (stickiness & FLOATINGTOP)))
  1330.     {
  1331.         t = b + height;
  1332.     }
  1333.     }
  1334.  
  1335.     if ((stickiness & STICKYTOP) || (stickiness & FLOATINGTOP))
  1336.     {
  1337.     if (stickiness & FLOATINGTOP)
  1338.     {
  1339.         t = (t - ob) * hr + bottom;
  1340.     }
  1341.     else
  1342.     {
  1343.         t += top - ot;
  1344.     }
  1345.     if (!((stickiness & STICKYBOTTOM) || (stickiness & FLOATINGBOTTOM)))
  1346.     {
  1347.         b = t - height;
  1348.     }
  1349.     }
  1350.     Set2DIntBounds(object, l, r, b, t);
  1351.  
  1352.     /*Possibly adjust the left width*/
  1353.     if (r - l - leftWidth < MINNOTNAMESPACE)
  1354.     {
  1355.     leftWidth = r - l - MINNOTNAMESPACE;
  1356.     SetVar(object, LEFTSIDEWIDTH, NewInt(leftWidth));
  1357.     }
  1358.  
  1359.     /*Adjust the readouts*/
  1360.     var = GetVar(object, READOUT);
  1361.     if (var)
  1362.     {
  1363.     Set2DIntBounds(var, l + TC_LEFTLABEL, l + leftWidth + TC_GAP + BARWIDTH,
  1364.     t - TC_TIMEHEIGHT + TC_GAP, t);
  1365.     }
  1366.  
  1367.     var = GetVar(object, READOUT2);
  1368.     if (var)
  1369.     {
  1370.     Set2DIntBounds(var, l + TC_LEFTLABEL, l + leftWidth + TC_GAP + BARWIDTH,
  1371.     t - TC_TIMEHEIGHT - TC_CURHEIGHT, t - TC_TIMEHEIGHT);
  1372.     }
  1373.  
  1374.     /*Adjust the buttons*/
  1375.     var = GetVar(object, SPARSERBUTTON);
  1376.     if (var)
  1377.     {
  1378.     Set2DIntBounds(var, l + leftWidth - TC_DBWIDTH,
  1379.         l + leftWidth, b, b + BARWIDTH);
  1380.     }
  1381.  
  1382.     var = GetVar(object, DENSERBUTTON);
  1383.     if (var)
  1384.     {
  1385.     Set2DIntBounds(var, l + leftWidth - TC_DBWIDTH * 2 - TC_GAP,
  1386.         l + BARWIDTH  + leftWidth - BARWIDTH - TC_DBWIDTH - TC_GAP,
  1387.         b, b + BARWIDTH);
  1388.     }
  1389.  
  1390.     /*Adjust the scroll bars*/
  1391.     var = GetVar(object, VSCROLL);
  1392.     if (var)
  1393.     {
  1394. #ifdef SCROLLINMIDDLE
  1395.     Set2DIntBounds(var, l + leftWidth + TC_GAP, l + leftWidth + TC_GAP + BARWIDTH,
  1396.                  b + BARWIDTH + TC_GAP,
  1397.                  t - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP);
  1398. #else
  1399.     Set2DIntBounds(var, l, l + BARWIDTH,
  1400.                  b + BARWIDTH + TC_GAP,
  1401.                  t - TC_TIMEHEIGHT - TC_CURHEIGHT - TC_GAP);
  1402. #endif
  1403.     }
  1404.     var = GetVar(object, HSCROLL);
  1405.     if (var)
  1406.     {
  1407.     Set2DIntBounds(var, l + leftWidth + 2 * TC_GAP + BARWIDTH, r,
  1408.                  b,
  1409.                  b + BARWIDTH);
  1410.     }
  1411.  
  1412.     RecalcScroll(object);
  1413.  
  1414.     return ObjTrue;
  1415. }
  1416.  
  1417. ObjPtr TrackControlBoundsInvalid(object, changeCount)
  1418. ObjPtr object;
  1419. unsigned long changeCount;
  1420. /*For a time control, tests to see if it needs drawing.  Returns
  1421.   NULLOBJ    if it does not
  1422.   array[4]    giving bounds if it does
  1423.   ObjTrue    it it needs to be redrawn but does not know where
  1424. */
  1425. {
  1426.     ObjPtr myBounds;
  1427.     real boundsElements[4];
  1428.     real testElements[4];
  1429.     ObjPtr test;
  1430.     real myBoundsElements[4];
  1431.     ObjPtr scrollBar, readout, button;
  1432.     Bool firstTime = true;
  1433.     Bool doubleNoBounds = false;
  1434.     ObjPtr tracks, repObj;
  1435.  
  1436.     MakeVar(object, APPEARANCE);
  1437.  
  1438.     MakeVar(object, CHANGEDBOUNDS);
  1439.     if (GetVarChangeCount(object, CHANGEDBOUNDS) > changeCount)
  1440.     {
  1441.     /*Object is not good, so return the bounds*/
  1442.  
  1443.     myBounds = GetVar(object, CHANGEDBOUNDS);
  1444.     if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  1445.         && DIMS(myBounds)[0] == 4)
  1446.     {
  1447.         return myBounds;
  1448.     }
  1449.     else
  1450.     {
  1451.         return ObjTrue;
  1452.     }
  1453.     }
  1454.  
  1455.     MakeVar(object, BOUNDS);
  1456.     myBounds = GetVar(object, BOUNDS);
  1457.     Array2CArray(myBoundsElements, myBounds);
  1458.  
  1459.  
  1460.     scrollBar = GetVar(object, HSCROLL);
  1461.     if (scrollBar);
  1462.     {
  1463.         test = BoundsInvalid(scrollBar, changeCount);
  1464.         if (test)
  1465.         {
  1466.         /*Hey, the scroll bar needs redrawing*/
  1467.         if (IsRealArray(test))
  1468.         {
  1469.             /*It has a bounds*/
  1470.             if (firstTime)
  1471.             {
  1472.             Array2CArray(boundsElements, test);
  1473.             }
  1474.             else
  1475.             {
  1476.             Array2CArray(testElements, test);
  1477.             if (testElements[0] < boundsElements[0])
  1478.                 boundsElements[0] = testElements[0];
  1479.             if (testElements[1] > boundsElements[1])
  1480.                 boundsElements[1] = testElements[1];
  1481.             if (testElements[2] < boundsElements[2])
  1482.                 boundsElements[2] = testElements[2];
  1483.             if (testElements[3] > boundsElements[3])
  1484.                 boundsElements[3] = testElements[3];
  1485.             }
  1486.         }
  1487.         else
  1488.         {
  1489.             /*It doesn't have a bounds*/
  1490.             if (firstTime)
  1491.             {
  1492.             /*Try to use my bounds*/
  1493.             if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  1494.                 && DIMS(myBounds)[0] == 4)
  1495.             {
  1496.                 Array2CArray(boundsElements, myBounds);
  1497.             }
  1498.             else
  1499.             {
  1500.                 doubleNoBounds = true;
  1501.             }
  1502.             }
  1503.         }
  1504.         firstTime = false;
  1505.         }
  1506.     }
  1507.  
  1508.     scrollBar = GetVar(object, VSCROLL);
  1509.     if (scrollBar);
  1510.     {
  1511.         test = BoundsInvalid(scrollBar, changeCount);
  1512.         if (test)
  1513.         {
  1514.         /*Hey, the scroll bar needs redrawing*/
  1515.         if (IsRealArray(test))
  1516.         {
  1517.             /*It has a bounds*/
  1518.             if (firstTime)
  1519.             {
  1520.             Array2CArray(boundsElements, test);
  1521.             }
  1522.             else
  1523.             {
  1524.             Array2CArray(testElements, test);
  1525.             if (testElements[0] < boundsElements[0])
  1526.                 boundsElements[0] = testElements[0];
  1527.             if (testElements[1] > boundsElements[1])
  1528.                 boundsElements[1] = testElements[1];
  1529.             if (testElements[2] < boundsElements[2])
  1530.                 boundsElements[2] = testElements[2];
  1531.             if (testElements[3] > boundsElements[3])
  1532.                 boundsElements[3] = testElements[3];
  1533.             }
  1534.         }
  1535.         else
  1536.         {
  1537.             /*It doesn't have a bounds*/
  1538.             if (firstTime)
  1539.             {
  1540.             /*Try to use my bounds*/
  1541.             if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  1542.                 && DIMS(myBounds)[0] == 4)
  1543.             {
  1544.                 Array2CArray(boundsElements, myBounds);
  1545.             }
  1546.             else
  1547.             {
  1548.                 doubleNoBounds = true;
  1549.             }
  1550.             }
  1551.         }
  1552.         firstTime = false;
  1553.         }
  1554.     }
  1555.  
  1556.     readout = GetVar(object, READOUT);
  1557.     if (readout)
  1558.     {
  1559.         test = BoundsInvalid(readout, changeCount);
  1560.         if (test)
  1561.         {
  1562.         /*Hey, the scroll bar needs redrawing*/
  1563.         if (IsRealArray(test))
  1564.         {
  1565.             /*It has a bounds*/
  1566.             if (firstTime)
  1567.             {
  1568.             Array2CArray(boundsElements, test);
  1569.             }
  1570.             else
  1571.             {
  1572.             Array2CArray(testElements, test);
  1573.             if (testElements[0] < boundsElements[0])
  1574.                 boundsElements[0] = testElements[0];
  1575.             if (testElements[1] > boundsElements[1])
  1576.                 boundsElements[1] = testElements[1];
  1577.             if (testElements[2] < boundsElements[2])
  1578.                 boundsElements[2] = testElements[2];
  1579.             if (testElements[3] > boundsElements[3])
  1580.                 boundsElements[3] = testElements[3];
  1581.             }
  1582.         }
  1583.         else
  1584.         {
  1585.             /*It doesn't have a bounds*/
  1586.             if (firstTime)
  1587.             {
  1588.             /*Try to use my bounds*/
  1589.             if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  1590.                 && DIMS(myBounds)[0] == 4)
  1591.             {
  1592.                 Array2CArray(boundsElements, myBounds);
  1593.             }
  1594.             else
  1595.             {
  1596.                 doubleNoBounds = true;
  1597.             }
  1598.             }
  1599.         }
  1600.         firstTime = false;
  1601.         }
  1602.     }
  1603.  
  1604.     readout = GetVar(object, READOUT2);
  1605.     if (readout)
  1606.     {
  1607.         test = BoundsInvalid(readout, changeCount);
  1608.         if (test)
  1609.         {
  1610.         /*Hey, the scroll bar needs redrawing*/
  1611.         if (IsRealArray(test))
  1612.         {
  1613.             /*It has a bounds*/
  1614.             if (firstTime)
  1615.             {
  1616.             Array2CArray(boundsElements, test);
  1617.             }
  1618.             else
  1619.             {
  1620.             Array2CArray(testElements, test);
  1621.             if (testElements[0] < boundsElements[0])
  1622.                 boundsElements[0] = testElements[0];
  1623.             if (testElements[1] > boundsElements[1])
  1624.                 boundsElements[1] = testElements[1];
  1625.             if (testElements[2] < boundsElements[2])
  1626.                 boundsElements[2] = testElements[2];
  1627.             if (testElements[3] > boundsElements[3])
  1628.                 boundsElements[3] = testElements[3];
  1629.             }
  1630.         }
  1631.         else
  1632.         {
  1633.             /*It doesn't have a bounds*/
  1634.             if (firstTime)
  1635.             {
  1636.             /*Try to use my bounds*/
  1637.             if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  1638.                 && DIMS(myBounds)[0] == 4)
  1639.             {
  1640.                 Array2CArray(boundsElements, myBounds);
  1641.             }
  1642.             else
  1643.             {
  1644.                 doubleNoBounds = true;
  1645.             }
  1646.             }
  1647.         }
  1648.         firstTime = false;
  1649.         }
  1650.     }
  1651.  
  1652.     button = GetVar(object, DENSERBUTTON);
  1653.     if (button)
  1654.     {
  1655.         test = BoundsInvalid(button, changeCount);
  1656.         if (test)
  1657.         {
  1658.         /*Hey, the scroll bar needs redrawing*/
  1659.         if (IsRealArray(test))
  1660.         {
  1661.             /*It has a bounds*/
  1662.             if (firstTime)
  1663.             {
  1664.             Array2CArray(boundsElements, test);
  1665.             }
  1666.             else
  1667.             {
  1668.             Array2CArray(testElements, test);
  1669.             if (testElements[0] < boundsElements[0])
  1670.                 boundsElements[0] = testElements[0];
  1671.             if (testElements[1] > boundsElements[1])
  1672.                 boundsElements[1] = testElements[1];
  1673.             if (testElements[2] < boundsElements[2])
  1674.                 boundsElements[2] = testElements[2];
  1675.             if (testElements[3] > boundsElements[3])
  1676.                 boundsElements[3] = testElements[3];
  1677.             }
  1678.         }
  1679.         else
  1680.         {
  1681.             /*It doesn't have a bounds*/
  1682.             if (firstTime)
  1683.             {
  1684.             /*Try to use my bounds*/
  1685.             if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  1686.                 && DIMS(myBounds)[0] == 4)
  1687.             {
  1688.                 Array2CArray(boundsElements, myBounds);
  1689.             }
  1690.             else
  1691.             {
  1692.                 doubleNoBounds = true;
  1693.             }
  1694.             }
  1695.         }
  1696.         firstTime = false;
  1697.         }
  1698.     }
  1699.  
  1700.     button = GetVar(object, SPARSERBUTTON);
  1701.     if (button)
  1702.     {
  1703.         test = BoundsInvalid(button, changeCount);
  1704.         if (test)
  1705.         {
  1706.         /*Hey, the scroll bar needs redrawing*/
  1707.         if (IsRealArray(test))
  1708.         {
  1709.             /*It has a bounds*/
  1710.             if (firstTime)
  1711.             {
  1712.             Array2CArray(boundsElements, test);
  1713.             }
  1714.             else
  1715.             {
  1716.             Array2CArray(testElements, test);
  1717.             if (testElements[0] < boundsElements[0])
  1718.                 boundsElements[0] = testElements[0];
  1719.             if (testElements[1] > boundsElements[1])
  1720.                 boundsElements[1] = testElements[1];
  1721.             if (testElements[2] < boundsElements[2])
  1722.                 boundsElements[2] = testElements[2];
  1723.             if (testElements[3] > boundsElements[3])
  1724.                 boundsElements[3] = testElements[3];
  1725.             }
  1726.         }
  1727.         else
  1728.         {
  1729.             /*It doesn't have a bounds*/
  1730.             if (firstTime)
  1731.             {
  1732.             /*Try to use my bounds*/
  1733.             if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  1734.                 && DIMS(myBounds)[0] == 4)
  1735.             {
  1736.                 Array2CArray(boundsElements, myBounds);
  1737.             }
  1738.             else
  1739.             {
  1740.                 doubleNoBounds = true;
  1741.             }
  1742.             }
  1743.         }
  1744.         firstTime = false;
  1745.         }
  1746.     }
  1747.  
  1748.     MakeVar(object, REPOBJ);
  1749.     repObj = GetVar(object, REPOBJ);
  1750.     if (repObj)
  1751.     {
  1752.     MakeVar(repObj, TRACKS);
  1753.     tracks = GetVar(repObj, TRACKS);
  1754.     if (tracks)
  1755.     {
  1756.     /*Draw the contents of the tracks*/
  1757.     int downOffset, y, height, lowestTrack, shownHeight;
  1758.     long k;
  1759.     ObjPtr var, *elements;
  1760.  
  1761.     if (scrollBar)
  1762.     {
  1763.         downOffset = (long) GetReal(GetValue(scrollBar));
  1764.     }
  1765.     else
  1766.     {
  1767.         downOffset = 0;
  1768.     }
  1769.  
  1770.     elements = ELEMENTS(tracks);
  1771.  
  1772.     /*Search for a place to begin*/
  1773.     y = -downOffset;
  1774.  
  1775.     for (k = 0; k < DIMS(tracks)[0]; ++k)
  1776.     {
  1777.         MakeVar(elements[k], TRACKHEIGHT);
  1778.         var = GetVar(elements[k], TRACKHEIGHT);
  1779.         if (var)
  1780.         {
  1781.         height = GetInt(var);
  1782.         if ((y - height) < 0) break;
  1783.         y -= height;
  1784.         }
  1785.     }
  1786.  
  1787.     if (k < DIMS(tracks)[0])
  1788.     {
  1789.         /*There's something to check*/
  1790.         FuncTyp method;
  1791.  
  1792.         lowestTrack = k;
  1793.  
  1794.         shownHeight = myBoundsElements[3] - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 
  1795.           (myBoundsElements[2] + TC_GAP + BARWIDTH) - 2;
  1796.  
  1797.         for (k = lowestTrack; (k < DIMS(tracks)[0]) && (y > -shownHeight); ++k)
  1798.         {
  1799.         MakeVar(elements[k], TRACKHEIGHT);
  1800.         var = GetVar(elements[k], TRACKHEIGHT);
  1801.         if (var)
  1802.         {
  1803.             height = GetInt(var);
  1804.         
  1805.             if (BoundsInvalid(elements[k], changeCount))
  1806.             {
  1807.             real tl, tr, tb, tt;
  1808.  
  1809.             tl = myBoundsElements[0] + 1;
  1810.             tr = myBoundsElements[1] - 1;
  1811.             tb = myBoundsElements[3] - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y - height,
  1812.             tt = myBoundsElements[3] - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1 + y;
  1813.             if (firstTime)
  1814.             {
  1815.                 boundsElements[0] = tl;
  1816.                 boundsElements[1] = tr;
  1817.                 boundsElements[2] = tb;
  1818.                 boundsElements[3] = tt;
  1819.                 firstTime = false;
  1820.             }
  1821.             else
  1822.             {
  1823.                 if (tl < boundsElements[0])
  1824.                 boundsElements[0] = tl;
  1825.                 if (tr > boundsElements[1])
  1826.                 boundsElements[1] = tr;
  1827.                 if (tb < boundsElements[2])
  1828.                 boundsElements[2] = tb;
  1829.                 if (tt > boundsElements[3])
  1830.                 boundsElements[3] = tt;
  1831.             }
  1832.             }
  1833.  
  1834.             y -= height;
  1835.         }
  1836.         }
  1837.     }
  1838.     }
  1839.     }
  1840.  
  1841.     /*Now return the bounds*/
  1842.     if (firstTime != true)
  1843.     {
  1844.         if (doubleNoBounds)
  1845.         {
  1846.         return ObjTrue;
  1847.         }
  1848.         else
  1849.         {
  1850.         ObjPtr retVal;
  1851.         retVal = NewRealArray(1, 4L);
  1852.         CArray2Array(retVal, boundsElements);
  1853.         return retVal;
  1854.         }
  1855.     }
  1856.  
  1857.     return NULLOBJ;
  1858. }
  1859.  
  1860. #ifdef PROTO
  1861. static void UpdateTrackReadouts(ObjPtr control)
  1862. #else
  1863. static void UpdateTrackReadouts(control)
  1864. ObjPtr control;
  1865. #endif
  1866. /*Updates the readouts in a track control*/
  1867. {
  1868.     ObjPtr readout1, readout2, clock, format, var;
  1869.     char timeStr[256];
  1870.     char frameStr[256];
  1871.     FuncTyp method;
  1872.     real frameWidth, time;
  1873.  
  1874.     readout1 = GetObjectVar("UpdateTrackReadouts", control, READOUT);
  1875.     if (!readout1)
  1876.     {
  1877.     return;
  1878.     }
  1879.  
  1880.     readout2 = GetVar(control, READOUT2);
  1881.  
  1882.     var = GetVar(control, VALUE);
  1883.     if (var)
  1884.     {
  1885.     time = GetReal(var);
  1886.  
  1887.     MakeVar(control, TIMEFORMAT);
  1888.     format = GetVar(control, TIMEFORMAT);
  1889.     if (format)
  1890.     {
  1891.         PrintTime(timeStr, time, GetInt(format));
  1892.     }
  1893.     else
  1894.     {
  1895.         sprintf(timeStr, "%g", time);
  1896.     }
  1897.  
  1898.     MakeVar(control, FRAMERATE);
  1899.     var = GetVar(control, FRAMERATE);
  1900.     if (var)
  1901.     {
  1902.         frameWidth = 1.0 / GetReal(var);
  1903.         sprintf(frameStr, "%g", floor(time / frameWidth + 0.5));
  1904.     }
  1905.     else
  1906.     {
  1907.         strcpy(frameStr, "");
  1908.     }
  1909.     }
  1910.     else
  1911.     {
  1912.     strcpy(timeStr, "");
  1913.     strcpy(frameStr, "");
  1914.     }
  1915.     InhibitLogging(true);
  1916.  
  1917.     if (readout1)
  1918.     {
  1919.     method = GetMethod(readout1, CHANGEDVALUE);
  1920.     SetMethod(readout1, CHANGEDVALUE, (FuncTyp) 0);
  1921.     SetTextBox(readout1, timeStr);
  1922.     SetMethod(readout1, CHANGEDVALUE, method);
  1923.     }
  1924.  
  1925.     if (readout2)
  1926.     {
  1927.     method = GetMethod(readout2, CHANGEDVALUE);
  1928.     SetMethod(readout2, CHANGEDVALUE, (FuncTyp) 0);
  1929.     SetTextBox(readout2, frameStr);
  1930.     SetMethod(readout2, CHANGEDVALUE, method);
  1931.     }
  1932.  
  1933.     InhibitLogging(false);
  1934. }
  1935.  
  1936.  
  1937. static ObjPtr KeyDownTrackControl(object, key, flags)
  1938. ObjPtr object;
  1939. int key;
  1940. long flags;
  1941. /*Does a keydown in a track control*/
  1942. {
  1943.     ObjPtr readout;
  1944.     if (key == 0)
  1945.     {
  1946.     /*Do nothing with timeout*/
  1947.     return ObjTrue;
  1948.     }
  1949.  
  1950.     if (AmICurrent(object) &&
  1951.     (key == FK_LEFT_ARROW || key == FK_RIGHT_ARROW ||
  1952.      key == FK_UP_ARROW || key == FK_DOWN_ARROW))
  1953.     {
  1954.     /*It's a keypress here*/
  1955.     ObjPtr var;
  1956.     real value, frameWidth;
  1957.  
  1958.     MakeVar(object, FRAMERATE);
  1959.     var = GetVar(object, FRAMERATE);
  1960.     if (!var)
  1961.     {
  1962.         return ObjTrue;
  1963.     }
  1964.     frameWidth = 1.0 / GetReal(var);
  1965.  
  1966.     var = GetRealVar("KeyDownTrackControl", object, VALUE);
  1967.     if (!var)
  1968.     {
  1969.         return ObjTrue;
  1970.     }
  1971.     value = GetReal(var);
  1972.  
  1973. #ifdef INTERACTIVE
  1974.     DrawInteractive(false);
  1975. #endif
  1976.     switch (key)
  1977.     {
  1978.         case FK_LEFT_ARROW:
  1979.         SetValue(object, NewReal((floor(value / frameWidth) - 1.0) * frameWidth));
  1980.         break;        
  1981.         case FK_RIGHT_ARROW:
  1982.         SetValue(object, NewReal((floor(value / frameWidth) + 1.0) * frameWidth));
  1983.         break;
  1984.     }
  1985.     AutoScroll(object);
  1986.     }
  1987.     readout = GetVar(object, READOUT);
  1988.     if (readout && AmICurrent(readout))
  1989.     {
  1990.     return KeyDownObject(readout, key, flags);
  1991.     }
  1992.  
  1993.     readout = GetVar(object, READOUT2);
  1994.     if (readout && AmICurrent(readout))
  1995.     {
  1996.     return KeyDownObject(readout, key, flags);
  1997.     }
  1998.     return ObjFalse;
  1999. }
  2000.  
  2001. static ObjPtr PressTrackControl(object, x, y, flags)
  2002. ObjPtr object;
  2003. int x, y;
  2004. long flags;
  2005. /*Does a press in a track control beginning at x and y.  Returns
  2006.   true iff the press really was in the control.*/
  2007. {
  2008. #ifdef INTERACTIVE
  2009.     int left, right, bottom, top;
  2010.     ObjPtr scrollbar, textBox, button;
  2011.     int leftWidth;
  2012.     ObjPtr var;
  2013.  
  2014.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  2015.  
  2016.     /*Kludge to make it not flash*/
  2017.     SetVar(object, OPAQUE, ObjTrue);
  2018.  
  2019.     /*See if it's a press in a scrollbar*/
  2020.     scrollbar = GetVar(object, HSCROLL);
  2021.     if (scrollbar)
  2022.     {
  2023.     if (IsTrue(PressObject(scrollbar, x, y, flags)))
  2024.     {
  2025.         return ObjTrue;
  2026.     }
  2027.     }
  2028.     scrollbar = GetVar(object, VSCROLL);
  2029.     if (scrollbar)
  2030.     {
  2031.     if (IsTrue(PressObject(scrollbar, x, y, flags)))
  2032.     {
  2033.         return ObjTrue;
  2034.     }
  2035.     }
  2036.  
  2037.     /*Now the readouts*/
  2038.     textBox = GetVar(object, READOUT);
  2039.     if (textBox)
  2040.     {
  2041.     if (IsTrue(PressObject(textBox, x, y, flags)))
  2042.     {
  2043.         return ObjTrue;
  2044.     }
  2045.     }
  2046.  
  2047.     textBox = GetVar(object, READOUT2);
  2048.     if (textBox)
  2049.     {
  2050.     if (IsTrue(PressObject(textBox, x, y, flags)))
  2051.     {
  2052.         return ObjTrue;
  2053.     }
  2054.     }
  2055.  
  2056.     /*Now the buttons*/
  2057.     button = GetVar(object, DENSERBUTTON);
  2058.     if (button)
  2059.     {
  2060.     if (IsTrue(PressObject(button, x, y, flags)))
  2061.     {
  2062.         return ObjTrue;
  2063.     }
  2064.     }
  2065.  
  2066.     /*Now the buttons*/
  2067.     button = GetVar(object, SPARSERBUTTON);
  2068.     if (button)
  2069.     {
  2070.     if (IsTrue(PressObject(button, x, y, flags)))
  2071.     {
  2072.         return ObjTrue;
  2073.     }
  2074.     }
  2075.  
  2076.     var = GetIntVar("DrawTrackControl", object, LEFTSIDEWIDTH);
  2077.     if (var)
  2078.     {
  2079.     leftWidth = GetInt(var);
  2080.     }
  2081.     else
  2082.     {
  2083.     leftWidth = 100;
  2084.     }
  2085.  
  2086.     if (x >= left && x <= right && y >= bottom && y <= top)
  2087.     {
  2088.     /*Hey!  It really was a click in the track control*/
  2089.     ObjPtr tracks;
  2090.     ObjPtr vScroll;
  2091.     long downOffset;
  2092.     ObjPtr repObj;
  2093.  
  2094.     if (TOOL(flags) == T_ROTATE)
  2095.     {
  2096.         flags |= F_EXTEND;
  2097.     }
  2098.  
  2099.     if (x >= left + leftWidth + TC_GAP && x <= left + leftWidth + TC_GAP + BARWIDTH &&
  2100.         y >= bottom && y <= bottom + BARWIDTH)
  2101.     {
  2102.         /*It's a press in the shape adjust control*/
  2103.         int newX, newY;
  2104.         int baseX;
  2105.         int newLeftWidth, oldLeftWidth;
  2106.         Bool insideP;
  2107.  
  2108.         SetVar(object, OPAQUE, ObjFalse);
  2109.  
  2110.         baseX = x;
  2111.         OverDraw(true);
  2112.  
  2113.         oldLeftWidth = leftWidth;
  2114.         insideP = true;
  2115.  
  2116.         EraseAll();
  2117. #ifdef SCROLLINMIDDLE
  2118.         FrameUIRect(left, left + leftWidth, bottom + TC_GAP + BARWIDTH,
  2119.         top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIRED);
  2120. #else
  2121.         FrameUIRect(left + BARWIDTH + TC_GAP, left + BARWIDTH + TC_GAP + leftWidth, bottom + TC_GAP + BARWIDTH,
  2122.         top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIRED);
  2123. #endif
  2124.  
  2125.         FrameUIRect(left + leftWidth + 2 * TC_GAP + BARWIDTH,
  2126.         right,
  2127.         bottom + TC_GAP + BARWIDTH,
  2128.         top, UIRED);
  2129.  
  2130.         while (Mouse(&newX, &newY))
  2131.         {
  2132.         if (newX != x || newY != y)
  2133.         {
  2134.             x = newX;
  2135.             y = newY;
  2136.  
  2137.             /*Mouse has moved.  First see about a transition*/
  2138.             if (insideP)
  2139.             {
  2140.             if (newX < left || newX > right ||
  2141.                 newY < bottom || newY > top)
  2142.             {
  2143.                 /*Transition to outside*/
  2144.                 insideP = false;
  2145.                 EraseAll();
  2146.                 leftWidth = oldLeftWidth;
  2147.  
  2148. #ifdef SCROLLINMIDDLE
  2149.                 FrameUIRect(left, left + leftWidth, bottom + TC_GAP + BARWIDTH,
  2150.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIRED);
  2151. #else
  2152.                 FrameUIRect(left + BARWIDTH + TC_GAP, left + BARWIDTH + TC_GAP + leftWidth, bottom + TC_GAP + BARWIDTH,
  2153.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIRED);
  2154. #endif
  2155.  
  2156.                 FrameUIRect(left + leftWidth + 2 * TC_GAP + BARWIDTH,
  2157.                 right,
  2158.                 bottom + TC_GAP + BARWIDTH,
  2159.                 top, UIRED);
  2160.                 
  2161.                 continue;
  2162.             }
  2163.             }
  2164.             else
  2165.             {
  2166.             if (newX < left || newX > right ||
  2167.                 newY < bottom || newY > top)
  2168.             {
  2169.                 /*Still outside*/
  2170.                 continue;
  2171.             }
  2172.             else
  2173.             {
  2174.                 insideP = true;
  2175.             }
  2176.             }
  2177.  
  2178.             /*Make a new left width*/
  2179.             newLeftWidth = oldLeftWidth + newX - baseX;
  2180.  
  2181.             if (newLeftWidth < MINNAMESPACE) newLeftWidth = MINNAMESPACE;
  2182.             if (newLeftWidth > right - left - MINNOTNAMESPACE) newLeftWidth = right - left - MINNOTNAMESPACE;
  2183.  
  2184.             if (newLeftWidth != leftWidth)
  2185.             {
  2186.             leftWidth = newLeftWidth;
  2187.             EraseAll();
  2188. #ifdef SCROLLINMIDDLE
  2189.                 FrameUIRect(left, left + leftWidth, bottom + TC_GAP + BARWIDTH,
  2190.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIRED);
  2191. #else
  2192.                 FrameUIRect(left + BARWIDTH + TC_GAP, left + BARWIDTH + TC_GAP + leftWidth, bottom + TC_GAP + BARWIDTH,
  2193.                 top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP, UIRED);
  2194. #endif
  2195.  
  2196.             FrameUIRect(left + leftWidth + 2 * TC_GAP + BARWIDTH,
  2197.                 right,
  2198.                 bottom + TC_GAP + BARWIDTH,
  2199.                 top, UIRED);
  2200.             }
  2201.         }
  2202.         }
  2203.  
  2204.         EraseAll();
  2205.         OverDraw(false);
  2206.  
  2207.         if (leftWidth != oldLeftWidth)
  2208.         {
  2209.         /*Have to set it*/
  2210.         int l, r, b, t;
  2211.  
  2212.         SetVar(object, LEFTSIDEWIDTH, NewInt(leftWidth));
  2213.  
  2214.         var = GetVar(object, READOUT);
  2215.         if (var)
  2216.         {
  2217.             Get2DIntBounds(var, &l, &r, &b, &t);
  2218.             r += leftWidth - oldLeftWidth;
  2219.             Set2DIntBounds(var, l, r, b, t);
  2220.         }
  2221.  
  2222.         var = GetVar(object, READOUT2);
  2223.         if (var)
  2224.         {
  2225.             Get2DIntBounds(var, &l, &r, &b, &t);
  2226.             r += leftWidth - oldLeftWidth;
  2227.             Set2DIntBounds(var, l, r, b, t);
  2228.         }
  2229.  
  2230.         /*Adjust the buttons*/
  2231.         var = GetVar(object, SPARSERBUTTON);
  2232.         if (var)
  2233.         {
  2234.             Get2DIntBounds(var, &l, &r, &b, &t);
  2235.             r += leftWidth - oldLeftWidth;
  2236.             l += leftWidth - oldLeftWidth;
  2237.             Set2DIntBounds(var, l, r, b, t);
  2238.         }
  2239.  
  2240.         var = GetVar(object, DENSERBUTTON);
  2241.         if (var)
  2242.         {
  2243.             Get2DIntBounds(var, &l, &r, &b, &t);
  2244.             r += leftWidth - oldLeftWidth;
  2245.             l += leftWidth - oldLeftWidth;
  2246.             Set2DIntBounds(var, l, r, b, t);
  2247.         }
  2248.  
  2249. #ifdef SCROLLINMIDDLE
  2250.         var = GetVar(object, VSCROLL);
  2251.         if (var)
  2252.         {
  2253.             Get2DIntBounds(var, &l, &r, &b, &t);
  2254.             l += leftWidth - oldLeftWidth;
  2255.             r += leftWidth - oldLeftWidth;
  2256.             Set2DIntBounds(var, l, r, b, t);
  2257.         }
  2258. #endif
  2259.  
  2260.         var = GetVar(object, HSCROLL);
  2261.         if (var)
  2262.         {
  2263.             Get2DIntBounds(var, &l, &r, &b, &t);
  2264.             l += leftWidth - oldLeftWidth;
  2265.             Set2DIntBounds(var, l, r, b, t);
  2266.         }
  2267.  
  2268.         ImInvalid(object);
  2269.         RecalcScroll(object);
  2270.         }
  2271.     }
  2272.  
  2273.     MakeMeCurrent(object);
  2274.  
  2275.     vScroll = GetVar(object, VSCROLL);
  2276.     if (vScroll)
  2277.     {
  2278.         downOffset = (long) GetReal(GetValue(vScroll));
  2279.     }
  2280.     else
  2281.     {
  2282.         downOffset = 0;
  2283.     }
  2284.  
  2285.     MakeVar(object, REPOBJ);
  2286.     repObj = GetVar(object, REPOBJ);
  2287.     if (!repObj) return ObjTrue;
  2288.  
  2289.     MakeVar(repObj, TRACKS);
  2290.     tracks = GetVar(repObj, TRACKS);
  2291.  
  2292.     if (tracks)
  2293.     {
  2294. #ifdef SCROLLINMIDDLE
  2295.         if (x >= left + 1 && x <= left + leftWidth - 1 &&
  2296.         y >= bottom + TC_GAP + BARWIDTH + 1 &&
  2297.         y <= top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1)
  2298. #else
  2299.         if (x >= left + BARWIDTH + TC_GAP + 1 &&
  2300.         x <= left + BARWIDTH + TC_GAP + leftWidth - 1 &&
  2301.         y >= bottom + TC_GAP + BARWIDTH + 1 &&
  2302.         y <= top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 1)
  2303. #endif
  2304.         {
  2305.         /*It's a press in the names*/
  2306.         int ty, height, k;
  2307.         ObjPtr *elements;
  2308.  
  2309.         elements = ELEMENTS(tracks);
  2310.  
  2311.         /*Search for a place to begin*/
  2312.         ty = -downOffset;
  2313.         y -= top - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 2;
  2314.         for (k = 0; k < DIMS(tracks)[0]; ++k)
  2315.         {
  2316.             MakeVar(elements[k], TRACKHEIGHT);
  2317.             var = GetVar(elements[k], TRACKHEIGHT);
  2318.             if (var)
  2319.             {
  2320.             height = GetInt(var);
  2321.             if ((ty - height) < y &&
  2322.                 (ty >= y)) break;
  2323.             ty -= height;
  2324.             }
  2325.         }
  2326.  
  2327.         if (k < DIMS(tracks)[0])
  2328.         {
  2329.             /*Found a click*/
  2330.             FuncTyp method;
  2331.  
  2332.             method = GetMethod(elements[k], PRESSNAME);
  2333.             if (method)
  2334.             {
  2335. #ifdef SCROLLINMIDDLE
  2336.             (*method)(elements[k], x - 1, y - ty, flags);
  2337. #else
  2338.             (*method)(elements[k], x - 1 - BARWIDTH - TC_GAP, y - ty, flags);
  2339. #endif
  2340.             }
  2341.         }
  2342.         else
  2343.         {
  2344.             if (!(flags & F_EXTEND))
  2345.             {
  2346.             DeselectAll();
  2347.             }
  2348.         }
  2349.         }
  2350.     }
  2351.  
  2352.     if (TOOL(flags) == T_HELP)
  2353.     {
  2354.         ContextHelp(object);
  2355.         return ObjTrue;
  2356.     }
  2357.  
  2358.     if(GetVar(object, VALUE) &&
  2359.        x >= left + leftWidth + 2 * TC_GAP + BARWIDTH &&
  2360.        x <= right &&
  2361.        y >= top - TC_TIMEHEIGHT - TC_CURHEIGHT &&
  2362.        y <= top - TC_TIMEHEIGHT)
  2363.     {
  2364.         /*It's a click in the current time slider*/
  2365.         ObjPtr var;
  2366.         real curTime, oldTime, lastTime;
  2367.         real loValue, hiValue;
  2368.         int timePixel;
  2369.         int xOffset;
  2370.         Bool inp;            /*True iff in*/
  2371.         int newX, newY;        /*New x and y*/
  2372.         real frameWidth;        /*Frame width*/
  2373.         int leftSide, rightSide;    /*Sides for scroll*/
  2374.  
  2375.         SaveForUndo(object);
  2376.  
  2377.         MakeVar(object, FRAMERATE);
  2378.         var = GetRealVar("PressTrackControl", object, FRAMERATE);
  2379.         if (var)
  2380.         {
  2381.         frameWidth = 1.0 / GetReal(var);
  2382.         }
  2383.         else
  2384.         {
  2385.         frameWidth = 30.0;
  2386.         }
  2387.  
  2388.         var = GetVar(object, VALUE);
  2389.         if (var)
  2390.         {
  2391.         curTime = GetReal(var);
  2392.         }
  2393.         else
  2394.         {
  2395.         curTime = 0.0;
  2396.         }
  2397.  
  2398.         var = GetVar(object, LOVALUE);
  2399.         if (var)
  2400.         {
  2401.         loValue = GetReal(var);
  2402.         }
  2403.         else
  2404.         {
  2405.         loValue = 0.0;
  2406.         }
  2407.  
  2408.         var = GetVar(object, HIVALUE);
  2409.         if (var)
  2410.         {
  2411.         hiValue = GetReal(var);
  2412.         }
  2413.         else
  2414.         {
  2415.         hiValue = 60.0;
  2416.         }
  2417.  
  2418.         timePixel = TimeToPixel(object, curTime);
  2419.  
  2420.         oldTime = curTime;
  2421.         lastTime = curTime;
  2422.  
  2423.         if (x >= timePixel - TCCURWIDTH / 2 && x <= timePixel + TCCURWIDTH / 2)
  2424.         {
  2425.         /*It's a click on the thumb.  Set offset*/
  2426.         xOffset = timePixel - x;
  2427.         }
  2428.         else
  2429.         {
  2430.         /*No offset*/
  2431.         xOffset = 0;
  2432.         }
  2433.  
  2434.         /*Start off inside*/
  2435.         inp = true;
  2436.         SetVar(object, HIGHLIGHTED, ObjTrue);
  2437.  
  2438.         DrawMe(object);
  2439.  
  2440.         /*Get bounds for scrolling*/
  2441.         leftSide = left + leftWidth + 2 * TC_GAP + BARWIDTH + 1 + TCSCROLLBORDER;
  2442.         rightSide =  right - 1 - TCSCROLLBORDER;
  2443.         if (x < leftSide) leftSide = x;
  2444.         if (x > rightSide) rightSide = x;
  2445.         var = NewRealArray(1, 2L);
  2446.         ((real *) ELEMENTS(var))[0] = leftSide;
  2447.         ((real *) ELEMENTS(var))[1] = rightSide;
  2448.         SetVar(object, SCROLLBOUNDS, var);
  2449.  
  2450.         /*Make current x and y bogus*/
  2451.         x = -12345; y = -12345;
  2452.         while (Mouse(&newX, &newY))
  2453.         {
  2454.         if (newX != x)
  2455.         {
  2456.             x = newX;
  2457.             y = newY;
  2458.  
  2459.             /*Check to see if it's outside*/
  2460.             if (y < top - TC_TIMEHEIGHT - TC_CURHEIGHT - SLOP ||
  2461.                y > top - TC_TIMEHEIGHT + SLOP)
  2462.             {
  2463.             /*Yes, it's outside*/
  2464.             if (inp)
  2465.             {
  2466.                 /*Transition from in to out*/
  2467.                 lastTime = oldTime;
  2468.                 SetVar(object, VALUE, NewReal(oldTime));
  2469.                 UpdateTrackReadouts(object);
  2470.                 SetVar(object, HIGHLIGHTED, ObjFalse);
  2471.                 inp = false;
  2472.  
  2473.                 if (AutoScroll(object))
  2474.                 {
  2475.                 x = -12345;
  2476.                 }
  2477.  
  2478.                 DrawMe(object);
  2479.             }
  2480.             }
  2481.             else
  2482.             {
  2483.             /*No, it's inside*/
  2484.             if (!inp)
  2485.             {
  2486.                 /*Transition from out to in*/
  2487.                 inp = true;
  2488.                 SetVar(object, HIGHLIGHTED, ObjTrue);
  2489.             }
  2490.             curTime = PixelToTime(object, x + xOffset);
  2491.             if (curTime < loValue - frameWidth * 0.5)
  2492.             {
  2493.                 curTime = loValue;
  2494.             }
  2495.             if (curTime > hiValue - frameWidth * 0.5)
  2496.             {
  2497.                 curTime = hiValue - frameWidth;
  2498.             }
  2499.             curTime = floor(curTime / frameWidth + 0.5) * frameWidth;
  2500.             if (curTime != lastTime)
  2501.             {
  2502.                 SetVar(object, VALUE, NewReal(curTime));
  2503.                 UpdateTrackReadouts(object);
  2504.  
  2505.                 if (AutoScroll(object))
  2506.                 {
  2507.                 x = -12345;
  2508.                 }
  2509.  
  2510.                 DrawMe(object);
  2511.                 lastTime = curTime;
  2512.             }
  2513.             }
  2514.         }
  2515.         }
  2516.         SetVar(object, SCROLLBOUNDS, NULLOBJ);
  2517.  
  2518.         if (inp)
  2519.         {
  2520.         SetVar(object, HIGHLIGHTED, ObjFalse);
  2521.         if (logging)
  2522.         {
  2523.             LogControl(object);
  2524.         }
  2525.         ChangedValue(object);
  2526.         }
  2527.         ImInvalid(object);
  2528.     }
  2529. #endif
  2530.  
  2531.     return ObjTrue;
  2532.     }
  2533.     else
  2534.     {
  2535.     return ObjFalse;
  2536.     }
  2537. }
  2538.  
  2539. static ObjPtr RecalcTrackControlScroll(control)
  2540. ObjPtr control;
  2541. /*Recalculates the scroll of the track control*/
  2542. {
  2543.     ObjPtr repObj, tracks, scrollBar, var;
  2544.     long totalHeight, shownHeight, k;
  2545.     ObjPtr *elements;
  2546.     int l, r, b, t;
  2547.     real sliderDown;
  2548.     real loValue, hiValue;
  2549.     real portionShown;
  2550.     int pixWidth;
  2551.     int leftWidth;
  2552.  
  2553.     Get2DIntBounds(control, &l, &r, &b, &t);
  2554.  
  2555.     repObj = GetObjectVar("RecalcTrackControlScroll", control, REPOBJ);
  2556.     if (!repObj) return ObjFalse;
  2557.  
  2558.     var = GetIntVar("RecalcTrackControlScroll", control, LEFTSIDEWIDTH);
  2559.     if (var)
  2560.     {
  2561.     leftWidth = GetInt(var);
  2562.     }
  2563.     else
  2564.     {
  2565.     leftWidth = 100;
  2566.     }
  2567.  
  2568.     /*Do vertical scroll*/
  2569.  
  2570.     /*Calculate the total height*/
  2571.     totalHeight = 0;
  2572.     tracks = GetVar(repObj, TRACKS);
  2573.     if (tracks)
  2574.     {
  2575.     elements = ELEMENTS(tracks);
  2576.     for (k = 0; k < DIMS(tracks)[0]; ++k)
  2577.     {
  2578.         MakeVar(elements[k], TRACKHEIGHT);
  2579.         var = GetVar(elements[k], TRACKHEIGHT);
  2580.         if (var && IsInt(var))
  2581.         {
  2582.         totalHeight += GetInt(var);
  2583.         }
  2584.     }
  2585.     }
  2586.  
  2587.     /*Slop at the bottom*/
  2588.     totalHeight += TC_CELLHEIGHT;
  2589.  
  2590.     /*Calculate the numbers for the vertical scroll bar*/
  2591.     shownHeight = t - TC_CURHEIGHT - TC_TIMEHEIGHT - TC_GAP - 
  2592.           (b + TC_GAP + BARWIDTH) - 2;
  2593.     sliderDown = shownHeight - totalHeight;
  2594.     if (sliderDown > 0.0) sliderDown = 0.0;
  2595.     portionShown = (real) shownHeight;
  2596.  
  2597.     /*Set the v scroll*/
  2598.     scrollBar = GetVar(control, VSCROLL);
  2599.     if (scrollBar)
  2600.     {
  2601.     SetSliderRange(scrollBar, 0.0, (real) sliderDown, TC_CELLHEIGHT);
  2602.     SetPortionShown(scrollBar, portionShown);
  2603.     }
  2604.  
  2605.     /*Do horizontal scroll*/
  2606.     var = GetRealVar("RecalcTrackControlScroll", control, LOVALUE);
  2607.     if (var)
  2608.     {
  2609.     loValue = GetReal(var);
  2610.     }
  2611.     else
  2612.     {
  2613.     loValue = 0.0;
  2614.     }
  2615.  
  2616.     var = GetRealVar("RecalcTrackControlScroll", control, HIVALUE);
  2617.     if (var)
  2618.     {
  2619.     hiValue = GetReal(var);
  2620.     }
  2621.     else
  2622.     {
  2623.     hiValue = 60.0;
  2624.     }
  2625.  
  2626.     pixWidth = (r - 1) - (l + leftWidth + 2 * TC_GAP + BARWIDTH + 1);
  2627.  
  2628.     var = GetRealVar("RecalcTrackControlScroll", control, TIMEPERPIXEL);
  2629.     if (var)
  2630.     {
  2631.     portionShown = GetReal(var) * pixWidth;
  2632.     }
  2633.     else
  2634.     {
  2635.     portionShown = hiValue - loValue;
  2636.     }
  2637.  
  2638.     scrollBar = GetVar(control, HSCROLL);
  2639.     if (scrollBar)
  2640.     {
  2641.     real min, max;
  2642.  
  2643.     min = loValue + portionShown * (0.5 - TC_MARGIN);
  2644.     max = hiValue - portionShown * (0.5 - TC_MARGIN);
  2645.     if (min > max)
  2646.     {
  2647.         min = (min + max) * 0.5;
  2648.         max = min;
  2649.     }
  2650.     SetSliderRange(scrollBar, min, max, portionShown / 10.0);
  2651.     SetPortionShown(scrollBar, portionShown);
  2652.     }
  2653.  
  2654.     return ObjTrue;
  2655. }
  2656.  
  2657. static ObjPtr AutoScrollTrackControl(control)
  2658. ObjPtr control;
  2659. /*Auto scrolls a time control*/
  2660. {
  2661.     ObjPtr var;
  2662.     int leftWidth;
  2663.     int leftSide, rightSide;
  2664.  
  2665.     var = GetIntVar("PixelToTime", control, LEFTSIDEWIDTH);
  2666.     if (var)
  2667.     {
  2668.     leftWidth = GetInt(var);
  2669.     }
  2670.     else
  2671.     {
  2672.     leftWidth = 100;
  2673.     }
  2674.  
  2675.     var = GetVar(control, VALUE);
  2676.     if (var)
  2677.     {
  2678.     int left, right, bottom, top, timePix;
  2679.     ObjPtr slider;
  2680.     real value, testVal, midVal, lo, hi;
  2681.  
  2682.     value = GetReal(var);
  2683.  
  2684.      Get2DIntBounds(control, &left, &right, &bottom, &top);
  2685.  
  2686.     slider = GetObjectVar("AutoScrollTimeControl", control, HSCROLL);
  2687.     if (!slider)
  2688.     {
  2689.         return ObjFalse;
  2690.     }
  2691.     
  2692.     GetSliderRange(slider, &lo, &hi);
  2693.  
  2694.     var = GetVar(control, SCROLLBOUNDS);
  2695.     if (var)
  2696.     {
  2697.         leftSide = ((real *) ELEMENTS(var))[0];
  2698.         rightSide = ((real *) ELEMENTS(var))[1];
  2699.     }
  2700.     else
  2701.     {
  2702.         leftSide = left + leftWidth + 2 * TC_GAP + BARWIDTH + 1 + TCSCROLLBORDER;
  2703.         rightSide =  right - 1 - TCSCROLLBORDER;
  2704.     }
  2705.  
  2706.     testVal = PixelToTime(control, leftSide);
  2707.     if (value < testVal)
  2708.     {
  2709.         /*It's off to the left*/
  2710.         SetSliderValue(slider, GetSliderValue(slider) + value - testVal);
  2711.         return ObjTrue;
  2712.     }
  2713.  
  2714.     testVal = PixelToTime(control, rightSide);
  2715.     if (value > testVal)
  2716.     {
  2717.         /*It's off to the right*/
  2718.         SetSliderValue(slider, GetSliderValue(slider) + value - testVal);
  2719.         return ObjTrue;
  2720.     }
  2721.  
  2722.     return ObjFalse;
  2723.     }
  2724.     else
  2725.     {
  2726.     return ObjFalse;
  2727.     }
  2728. }
  2729.  
  2730. static ObjPtr MakeTrackControlAppearance(control)
  2731. ObjPtr control;
  2732. /*Makes the appearance of a track control*/
  2733. {
  2734.     RecalcScroll(control);
  2735.     SetVar(control, APPEARANCE, ObjTrue);
  2736.     return ObjTrue;
  2737. }
  2738.  
  2739. void InitTrackControls()
  2740. /*Initializes the track controls*/
  2741. {
  2742.     pictureButtonClass = NewObject(buttonClass, 0L);
  2743.     AddToReferenceList(pictureButtonClass);
  2744.     SetMethod(pictureButtonClass, DRAW, DrawPictureButton);
  2745.  
  2746.     densityButtonClass = NewObject(pictureButtonClass, 0L);
  2747.     AddToReferenceList(densityButtonClass);
  2748.     SetMethod(densityButtonClass, DRAWCONTENTS, DrawDensityButtonContents);
  2749.  
  2750.     trackControlClass = NewObject(controlClass, 0L);
  2751.     AddToReferenceList(trackControlClass);
  2752.     SetVar(trackControlClass, LEFTSIDEWIDTH, NewInt(110));
  2753.     SetMethod(trackControlClass, DRAW, DrawTrackControl);
  2754.     SetMethod(trackControlClass, PRESS, PressTrackControl);
  2755.     SetMethod(trackControlClass, BOUNDSINVALID, TrackControlBoundsInvalid);
  2756.     SetMethod(trackControlClass, RESHAPE, ReshapeTrackControl);
  2757.     DeclareDependency(trackControlClass, APPEARANCE, HIGHLIGHTED);
  2758.     DeclareIndirectDependency(trackControlClass, APPEARANCE, REPOBJ, TRACKS);
  2759.     SetMethod(trackControlClass, APPEARANCE, MakeTrackControlAppearance);
  2760.     SetMethod(trackControlClass, RECALCSCROLL, RecalcTrackControlScroll);
  2761.     SetMethod(trackControlClass, AUTOSCROLL, AutoScrollTrackControl);
  2762.     SetMethod(trackControlClass, KEYDOWN, KeyDownTrackControl);
  2763.     SetVar(trackControlClass, OPAQUE, ObjTrue);
  2764.  
  2765.     AddSnapVar(trackControlClass, TIMEPERPIXEL);
  2766. }
  2767.  
  2768. void KillTrackControls()
  2769. /*Kills the track controls*/
  2770. {
  2771.     RemoveFromReferenceList(trackControlClass);
  2772.     RemoveFromReferenceList(densityButtonClass);
  2773.     RemoveFromReferenceList(pictureButtonClass);
  2774. }
  2775.